マジックナンバー0x10000004の怪
2015/12/12(土) 23:28 NetBSD はてブ情報 はてブに登録 はてブ数

このエントリはNetBSD Advent Calendar 2015の12日目です。

前回のNetBSD Advent Calendar 8日目からの続きです。

今回の結論は、前回の考察は全くの無意味で、実は何もしなくてよかった、です。

エントリは短いのですが、かなりヤクの毛を刈りましたよ

おさらい

前回のストーリはこんな感じです。
  • 移植の際、ステータスレジスタに0x10000004を入れる必要があった
  • マジックナンバーなので気になって調べた
  • NetBSD, FreeBSD, u-bootのレジスタ設定に共通点はなかった(u-bootはマジックナンバーの出元ですね)
ということで、もっぱらソースとマニュアルを紐解くという、いわば机上での調査でした。

そこで、今回は実際にあれころ動作させてみて何かわかることはないか、という実機での調査をしようと考えたわけです。

最新のソースで試してみよう

以前に試していたのはずいぶん古い環境だったので、気を取り直して新しめのソースコードで試してみよう、と思ったのが間違いの始まりでした。

NetBSD 7.0リリース版を入れて放置していたVMイメージを起動し、2012-12-11のソースを展開。クロスコンパイラをbuild.shで一発作成して、gitから取り出したLinino ONE用のパッチをあてます。パッチはきれいにあたってカーネルの作成にも成功しました。

順調です。

いざ、起動します。
Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
    The NetBSD Foundation, Inc.  All rights reserved.
Copyright (c) 1982, 1986, 1989, 1991, 1993
    The Regents of the University of California.  All rights reserved.

NetBSD 7.99.24 (INSTALL_LININO1) #0: Sat Dec 12 02:40:05 UTC 2015
        root@n70:/export/o/20151211/evbmips/sys/arch/evbmips/compile/INSTALL_LININO1
Atheros AR9331
total memory = 65536 KB
avail memory = 56424 KB
mainbus0 (root)
cpu0 at mainbus0: 400.00MHz (hz cycles = 2000000, delay divisor = 200)
cpu0: MIPS 24K (0x19374) Rev. 116 with software emulated floating point
cpu0: 16 TLB entries, 256MB max page size
cpu0: 64KB/32B 4-way set-associative L1 instruction cache
cpu0: 32KB/32B 4-way set-associative write-back L1 data cache
wdog0 at mainbus0: 5 second period
arbus0 at mainbus0
あれ? このあと文字化けした表示が続き、まるで動きません。

このあと、パッチの当て忘れに気づいたり、あれこれ試行錯誤したのですが、結局のところシェルプロンプトを拝むことはできませんでした。

これはまずい。

昔の環境なら動くはず

以前動作させていた環境なら動くはずです。動いているところから色々変化させて挙動の変化を見るほうが良いに決まっています。初めからそうすればよかったのです。

と、いうことで以前のVMイメージを起動して、当時作ったカーネルを起動します。はい、当然のことながら起動します。

それでは、ステータスレジスタを変化させてみましょう。

ということで、ステータスレジスタを変化させて試してみますが、なんだか様子が変です。

以前は止まっていたはずなのに、なにをやっても正しく起動してきます。

おかしい。

頭から見てみよう

カーネルの作成ミスや修正のセーブし忘れなど、ケアレスミスを見つけやすくするためにカーネルの作成回数や「ここを実行したよ」というデバッグ文字を出しています。

ここをよく見るとおかしなことが。

なぜか通るべきルートを通っているはずなのに、デバッグ文字が出力されていません。

シリアル部分が詰まっているのかなぁ、と思っていたのですが、いよいよ疑わねばならない感じです。リブートではなく電源OFFからやり直してみたり、ここまででずいぶん時間を食っています。

デバッグ文字が出力されていない理由、それはその部分を実行していないだけなのです。つまり、違うルートを通っていると。

絶対通らないはずと思い込んでいたルートにデバッグ文字を入れると、きっちりそこの文字が出ました。あぁ、やっぱりか。

そのルートが問題

実行されないところを一生懸命直したりしてバカだなぁ、ということにつきるのですが、問題はそのルートです。
     89 #else
     90 	mtc0	zero, MIPS_COP_0_STATUS		# Disable interrupts
     91 	COP0_SYNC
     92 #endif
そうです、ステータスレジスタにゼロを入れて完全にクリアしています。

前回、NetBSDではステータスレジスタのBEVフィールドを保持して書き戻していると書きましたが、あれは大ウソだったということです。

それはそれでマヌケな話なのですが、それはさておき、ステータスレジスタにゼロを入れてシェルプロンプトが出るところまで動いているということはどういうことなんでしょうか?

Linino ONEを移植する際に、最初につまづいたのは「ステータスレジスタにゼロを入れて書き戻すとハングする」という事象だったはずです。

西村さんのエスパーメールにも、ステータスレジスタの全ビットを書き換えるコードの是非について言及があったので、当時もこのルートを通り、うまくうごかずu-bootをまねて0x10000004を設定して動かしたはずです。

怪奇現象

時間がたつとバグが消えるなんて話は、本当ならばうれしいですが、おかしな話です。

まぁいいです。私はマジックナンバーを設定したいのです。

以前そうしていたように0x10000004を設定してカーネルを起動します。
total memory = 65536 KB
avail memory = 56456 KB
pid 0(system): trap: cpu0, reserved instruction in kernel mode
status=0x10000003, cause=0x70008028, epc=0x8006e6f0, vaddr=0xc0001ff8
tf=0x807bbaa0 ksp=0x807bbb40 ra=0x8006e6c4 ppl=0
kernel: reserved instruction trap
Stopped in pid 0.1 (system) at  8006e6f0:       sw      s0,0(s2)
db>
あれ、死んだ。

以前と真逆の結果です。

こうなったらいろいろ試してみよう

せっかくなので、前回調べたFreeBSDの初期化を試してみたり、マジックナンバーのCU0とERLの片方だけをONにしたり、FreeBSDの設定にCU0, ERLを追加してみたりしました。
ステータスレジスタ結果
ゼロ起動する
CU0=0N起動する
ERL=ON起動しない (1)
CU0=ON && ERL=ON起動しない(2)
FreeBSDの初期化起動する
FreeBSDの初期化 + CU0=ON起動する
FreeBSDの初期化 + ERL=ON起動しない(3)
起動しないパターンの共通項はERL=ONのようです。

なお、死んだときのメッセージについては次のとおりです。

(1)ERL=ON
pid 0(system): trap: cpu0, reserved instruction in kernel mode
status=0x10000003, cause=0x70008028, epc=0x8006e6f0, vaddr=0xc0001ff8
tf=0x807bbaa0 ksp=0x807bbb40 ra=0x8006e6c4 ppl=0
kernel: reserved instruction trap
Stopped in pid 0.1 (system) at  8006e6f0:       sw      s0,0(s2)
(2)CU0=ON && ERL=ON
pid 0(system): trap: cpu0, reserved instruction in kernel mode
status=0x3, cause=0x70008028, epc=0x8006e700, vaddr=0xc0001ff8
tf=0x807bbaa0 ksp=0x807bbb40 ra=0x8006e6d4 ppl=0
kernel: reserved instruction trap
Stopped in pid 0.1 (system) at  8006e700:       sw      s0,0(s2)
(3)FreeBSDの初期化 + ERL=ON
pid 0(system): trap: cpu0, system call in kernel mode
status=0x3, cause=0x50008020, epc=0x8006e6f0, vaddr=0xc0001ff8
tf=0x807bbaa0 ksp=0x807bbb40 ra=0x8006e6c4 ppl=0
kernel: system call trap
Stopped in pid 0.1 (system) at  8006e6f0:       sw      s0,0(s2)
ほとんど同じに見えますがstatus, causeのが微妙に違っています。

まとめ

さて、いろいろと試してみましたけれど、実際に動かしてみてわかったことは、「元のコードが正しかった」ということのようです。

西村さんからもらったエスパーメールはマジックナンバーのメールだけでなく、実はそのあとにも数通いただいていたのです。

そのメールの内容は、当時はさっぱり理解できなかったのですが、いま改めて読み返してみると、テクニカルかつ示唆に富む内容だなぁと噛みしめている次第です。

個人あてメールを勝手に引用するのはマナー違反だと知りつつ、一文だけ引用させていただいて、今回のエントリーを締めたいと思います。
自分で拵えたコードは多くないはずですから、総当りして間違っていないか確認してみてはどうでしょうか?
西村さんからのメールより

蛇足

「酔った勢いでエントリー」はやめておこう!

名前:  非公開コメント   

  • TB-URL  http://www.tokuda.net/diary/0856/tb/