2026/03/21

TangConsoleDCJ11MEMにおける2BSDの誤動作の調査 その1

2.9BSDの誤動作

オリジナルのFPGAで2.9BSDの誤動作が確認できました。確実に再現します。

再現方法と実行結果

 シングルユーザモードで起動後、以下のように実行します。

# mount -a
Mounted /usr on /dev/rp1h
# cd /usr/src/sys/GENERIC; make clean; make
rm -f *.o *.i
cc -V -S -O -DKERNEL -I. -I/usr/include ../sys/sys2.c
ed - < :splfix.movb sys2.s
as -V - -o sys2.o sys2.s
rm sys2.s

(snip)

cc -V -S -O -DKERNEL -I. -I/usr/include ../dev/ttynew.c
ed - < :splfix.movb ttynew.s
as -V - -o ttynew.o ttynew.s
rm ttynew.s
cc -V -S -O -DKERNEL -I. -I/usr/include ../dev/tty.c
ed - < :splfix.movb tty.s
Illegal instruction - core dumped
# strings core | head
@q6N
core
core
make
h
 h
  .

R0
MAKE.  VERSION 2.58     14 MARCH 1979
=|^();&<>*?[]:$`'"\
 :;&>|
No description argument after -f flag

# adb /bin/make core
$R
ps      0170011
pc      034110
sp      0171272
r5      0171306
r4      0171370
r3      0
r2      0
r1      06
r0      01560
034110:         mov     sp,r5
# make
cc -V -S -O -DKERNEL -I. -I/usr/include ../dev/tty.c
ed - < :splfix.movb tty.s
as -V - -o tty.o tty.s
rm tty.s

カーネルをビルドするとmakeが異常終了します。

コアダンプを調べても実行した命令は正常です。また、続けてmakeを実行すると正常に動作するので、ファイル上にもメモリ上にも不正な命令は存在しないものと考えられます。

2.11BSDの誤動作

 改造版のFPGAとPCBで2.11BSDの誤動作を確実に再現できる方法が見つかりました。

 再現方法と実行結果

 シングルユーザモードで起動後、以下のように実行します。

 @773010
73Boot from rk(0,0,0) at 0177404
:
: rk(0,0,0)unix
Boot: bootdev=03000 bootcsr=0177404

2.11 BSD UNIX #32: Fri Mar 13 00:15:09 PST 2026
    root@:/usr/src/sys/SMALL


phys mem  = 655360
avail mem = 414912
user mem  = 307200

March 15 18:32:17 init: configure system

hk ? csr 177440 vector 210 skipped:  No autoconfig routines.
ht ? csr 172440 vector 224 skipped:  No autoconfig routines.
ra ? csr 172150 vector 154 skipped:  No autoconfig routines.
rl ? csr 174400 vector 160 skipped:  No autoconfig routines.
tm 0 csr 172520 vector 224 attached
tms ? csr 174500 vector 260 skipped:  No autoconfig routines.
ts ? csr 172520 vector 224 skipped:  No autoconfig routines.
xp ? csr 176700 vector 254 skipped:  No autoconfig routines.
erase, kill ^U, intr ^C
# halt
IOT trap - core dumped
# ls *.core
halt.core
# adb /sbin/halt halt.core
adb: no memory for symbols
adb> $r
ps      0170000
pc      041174
sp      0174510
r5      0175214
r4      0175262
r3      040312
r2      045
r1      0
r0      0144
041174:         add     $010,r4
adb> #
#

haltコマンドがIOT命令(000004)を実行して異常終了します。

ODTでメモリダンプを調べてみましたが、異常終了したプロセスの該当するPCの命令はファイル上の命令と一致していました。 

48chのロジックアナライザを接続してすべての信号を観測できる環境を作り、カーネルとFPGAに仕込みを入れてロジアナにトリガをかけてみましたが、バス上で観測された命令はファイル上の命令と一致しており、IOT命令ではありませんでした。

バスのトランザクションとしては以下のような流れでした。

  1. PC(041174)近傍の4命令が読み出される
  2. IOT trapのベクタの2 word(PC, SR)が読み出される
  3. IOT trapベクタに設定されているロジアナトリガ用の命令列が読み出される
  4. トリガ用のI/Oアドレスに書き込みが実行されてトリガ信号がアサートされる 

念のためにIOT命令を実行するテストプログラムを作成してロジアナで解析しましたが、こちらはきちんとIOT命令を読み込んでいることが確認できたので、解析方法に誤りはないと思います。 

考察

 以上の観測結果から考えて、どちらの誤動作も

メモリから読み出したものとは異なる命令を実行した

のが現象のように見えます。この仮説が正しいとして、原因が何かを考えてみたのですが、現時点では何も思いつきません。

(4月6日追記) IOT Trap発生時にカーネルスタックに保存されるPCは、IOT命令のアドレスではなく、+2した値のようなので、上記の解釈は誤りでした。-2したアドレスにはIOT命令が存在することが確認できました。

なお、以上の現象は2セットの個体を用いて検証しているので、ハードウェアの個体差やCPUの故障などは考えにくいと思われます。

(追記) "/.profile"を編集してPATHに2文字追加しただけで再現しなくなったりします。再現条件はかなり限定されるようです。

9 件のコメント:

  1. 検証ありがとうございます。
    2.11だと、haltコマンドで(無いはずの)IOT命令が実行されているっぽい。
    2.9だと、ed - < :splfix.movb tty.s で
    Illegal instruction - core dumped
    になる。という理解でよろしいでしょうか?
    こちらは2.11の環境が無いので、2.9が再現するか試してみようと思います。

    返信削除
    返信
    1. 2.9の場合、異常終了したのはmakeです。異常終了後に実行した"strings core | head"で"MAKE. VERSION 2.58..."の文字列が表示されているので、makeが「犯人」であると示したつもりでしたが、わかりにくかったですね。

      削除
  2. 2.9で再現を試みたのですが、そもそも2.9が起動しなくなってしまっていて、再インストールしてもpanicで起動しないという状況に陥ってしまいました。

    返信削除
    返信
    1. 念のための確認ですが、ブートする前に"@100050g"などを実行してモデルを設定しましたか?私もよく忘れて起動に失敗します。

      削除
    2. それから、ハードウェアの機嫌が悪い時に私が試してうまくいったことがあるのは、1)USBケーブルを抜き差ししてみる 2)bitstreamの再書き込み 3)reconfigボタンを数秒間長押ししてみる です。

      削除
    3. 実は昨日は一応起動できたのですが、綺麗にしてから試そうと思ってOSを再インストールしたら起動しなくなったという次第です。1)と2)はやっているのですが、3)はやってないので後で試してみます。

      削除
  3. 2.9BSDで同様の現象が確認できました。
    今日も10回に1度くらいしか起動しないような不安定な状態だったのですが、試しにSDメモリのクロック周波数を下げてみたら起動するようになって、カーネルのmakeも途中まで動きました。
    変更点はtop.vの174行目をコメントアウトして、175行目を生かしたのみです。
    // parameter SD_MEM_FRQ =1000_000;
    parameter SD_MEM_FRQ = 800_000;

    実はその前に水晶を取り替えてSYS_CLK_FRQを16MHzにしてみたのですが、うまく動かなかったので水晶とSYS_CLK_FRQは18MHzのままです。
    makeは途中でcoreを吐きました。
    # cd /usr/src/sys/GENERIC
    # make clean
    rm -f *.o *.i
    # make
    (略)
    rm ttynew.s
    cc -V -S -O -DKERNEL -I. -I/usr/include ../dev/tty.c
    ed - < :splfix.movb tty.s
    as -V - -o tty.o tty.s
    rm tty.s
    cc -V -S -O -DKERNEL -I. -I/usr/include ../sys/prim.c
    ed - < :splfix.movb prim.s
    Illegal instruction - core dumped

    似たような箇所ですが微妙に違うところで止まっています。
    思うに、メモリが足りなくなったとかそういう類のことが原因な気がしますがどうでしょうか。

    返信削除
    返信
    1. メモリが足りない場合は、きちんと"Out of memory."というエラーメッセージが出ます。不正な命令を実行したりはしません。2.9BSDの場合は、マルチユーザモードでログインしてみてください。メモリ不足でログインできません。その際、エラーメッセージが表示されます。シングルユーザモードでビルドしているのはメモリ不足を回避するためです。
      バイナリパッチでメモリを書き換えることで"illegal instruction trap"を捕まえる方法を考案したのでこれから記事にします。しばしお待ちください。

      削除
    2. 記事を書きました。この方法が成功すればHALT信号をトリガにして調べることができます。

      削除

TangConsoleDCJ11MEMにおける2BSDの誤動作の調査 その3

誤動作の原因の二つ目が判明しました。 符号なし2進数と符号付2進数の比較 後述するSOFUB_MAPの実装に符号なし2進数と符号付2進数を比較しているコードがありました。直接の比較ではありませんでしたが、符号なし整数の値を符号付整数の変数に代入し、その変数と定数を比較していたため...