最後の楽園の開拓を(ちょこっとだけ)手伝った話
相変わらず謎マシンいじりが最近の趣味のN君。
家の中の"積みマシン"の電源を入れてみたところ、
珍しいCPUを積んでいる事が分かりました。
>> hinv System: IP26 Processor: 75 Mhz R8000, with FPU Primary I-cache size: 16 Kbytes Primary D-cache size: 16 Kbytes Secondary cache size: 2 Mbytes Memory size: 512 Mbytes Graphics: GR5-XZ SCSI Disk: scsi(0)disk(1) Audio: Iris Audio Processor: version A2 revision 1.1.0
MIPS R8000というCPUはMIPS系のCPUの中では、かなり変わり者です。
R8000 - Wikipedia
Power Indigo2 (R8000) - Nekochan Net
"命令キャッシュは16KBで、ダイレクトマップ方式、仮想インデックス・仮想タグ方式で、ラインサイズは32バイトである。"
とか
"TLBはデュアルポートで384エントリあり、3ウェイセットアソシアティブ方式になっている。"
とか
"ストリーミングキャッシュは外付けの1MBから16MBのキャッシュで、R8000の二次キャッシュ、R8010の一次データキャッシュとして機能する。"
とか
"マルチチップで構成されている"
とか
変態度が高くて、イカしています。
暇を見つけて以下記事のようにボチボチ遊んでいたのですが、一部問題が有るものの動き始めました。
OpenBSD/sgi、カーネルのクロスコンパイルと起動方法について - nullnilaki’s blog
OpenBSD/sgi、IP26カーネルインストールにまつわるトラブル - nullnilaki’s blog
というわけで前置きが長くなりましたが、
"最後の楽園の開拓を(ちょこっとだけ)手伝った話"と題しまして、
NetBSD Advent Calendar 2015 - Qiita
23目に寄稿させてもらいます。
自分が触り始めた時は、OpenBSDにはR8000対応のソースは入っているものの、
自分でMakefileを修正しないとカーネルは作成されない状態で、
手つかずのまま3年程度眠っていた状態でした。
また、commit logには、
IP26 kernels currently boot single-user, but don't live long; I am suspecting a bug in the tcc cache routines, but am currently not able to find it (come to think of it, my understanding of how this cache works could be wrong, and of course there is no documentation for it but what can be gathered from IRIX'comments and defines).
と書いてある状態でした。
/src/sys/arch/sgi/localbus/tcc.c
— lucky owner (@nullnilaki) August 20, 2015
で、まずはキャッシュが怪しいかなと思って
(特に命令キャッシュはダイレクトマップ、仮想インデックス、仮想タグ方式なので)
いろいろいじってみたのですが、R8000のマニュアルとOpenBSDのキャッシュのフラッシュ方法が同じだったのと、
カーネルのPanicのしかたがキャッシュに起因するものでは無いような気がして、
キャッシュが原因説は保留しました。
/src/sys/arch/mips64/mips64/cache_tfp_subr.S
ふむ... pic.twitter.com/EmgGa8HeZ8
— lucky owner (@nullnilaki) December 21, 2015
さて、よくよく落ち方を観察すると、最終的にPanicはするのですが、
結構良いところまで行く場合が有る事に気付きました。
panic: trap: utlbmod: unmanaged page syncing disks... done tlbもいじる必要が有るか...
— lucky owner (@nullnilaki) August 25, 2015
>> bootp()bsd.rd.IP26 Obtaining bsd.rd.IP26 from server macbook2006 3577592+722344 entry: 0xa800000008010000 ARCS64 Firmware Found SGI-IP26, setting up. ... Bus error (core dumped) starting early daemons: syslogd pflogd. starting RPC daemons:. savecore: /dev/sd0a: Device busy checking quotas: done. kvm_mkdb: can't open /dev/ksyms panic: trap: utlbmod: invalid pte Stopped at 0xa800000008294424: jr ra 0xa800000008294428: move zero,zero RUN AT LEAST 'trace' AND 'ps' AND INCLUDE OUTPUT WHEN REPORTING THIS PANIC! DO NOT EVEN BOTHER REPORTING THIS WITHOUT INCLUDING THAT INFORMATION! ddb>
TLB modified faultについて、調べてみると
@nullnilaki なんとなくclean->dirtyに変化したイベントのようにきこえます
— 鯉江 (@koie) August 25, 2015
@koieさん、ありがとうございます!
どうやら、ユーザーランドTLBミス時の処理が良くないのが原因なような気がします。
そこで、今度はユーザーランドTLBミス時の処理を調べる事にしました。
/src/sys/arch/mips64/mips64/exception_tfp.S
utlb_miss: .set noat .align 4 PRE_MFC0_ADDR_HAZARD DMFC0 k0, COP_0_VADDR MFC0_HAZARD DMTC0 k0, COP_0_WORK0 MTC0_HAZARD PTR_SRL k0, SEGSHIFT sltiu k1, k0, PMAP_SEGTABSIZE beqz k1, _inv_seg NOP DMFC0 k1, COP_0_UBASE # PCB_SEGTAB(CI_CURPROCPADDR(curcpu)) MFC0_HAZARD PTR_SLL k0, LOGREGSZ PTR_ADDU k1, k0 PTR_L k1, 0(k1) # get pointer to page table DMFC0 k0, COP_0_WORK0 # saved COP_0_VADDR MFC0_HAZARD beqz k1, _inv_seg PTR_SRL k0, PAGE_SHIFT - 2 andi k0, ((NPTEPG / 2) - 1) << 2 PTR_ADDU k1, k0 lwu k0, 0(k1) # get pte DMTC0 k0, COP_0_TLB_LO MTC0_HAZARD TLBW ERET
このあたりの処理は、一刻も早く終わらせる為に全部アセンブリ言語で書かれているようです...
ウーン、わからん!呪文みたいだ...
ですが、MIPSの解説本を片手に読み進めていくと、
「なんとなく意味が分かるところ」と「わけがわからないよ」
な部分に分かれて来ました。
上記コードの赤文字の部分が「わけがわからないよ」な部分です。
やたらと"2"で引いたり、割ったり、左シフトしたりしています。
アセンブリ言語で書かれていてコードの意味は解らないし、デバックもやりづらいし、
お手上げです。
そこで思いつきました!
"一刻も早く終わらせる為に全部アセンブリ言語で書かれている"
なら
"同じような処理をCで書いている部分"を探して
参考にしてみれば良いんです。
そして、あっちこっち探して、見つけました!
/src/sys/arch/mips64/include/pmap.h
/* User virtual address to pte page entry */
#define uvtopte(va) (((va) >> PAGE_SHIFT) & (NPTEPG -1))
あれ?
/src/sys/arch/mips64/include/pmap.hに書かれているマクロでは
"2"で引いたり、割ったり、左シフトしたりしていません。
そこで、mips64/exception_tfp.Sを書き直してみました。
utlb_miss: .set noat ... PTR_L k1, 0(k1) # get pointer to page table DMFC0 k0, COP_0_WORK0 # saved COP_0_VADDR MFC0_HAZARD beqz k1, _inv_seg - PTR_SRL k0, PAGE_SHIFT - 2 - andi k0, ((NPTEPG / 2) - 1) << 2 + PTR_SRL k0, PAGE_SHIFT + andi k0, NPTEPG - 1 PTR_ADDU k1, k0 lwu k0, 0(k1) # get pte DMTC0 k0, COP_0_TLB_LO MTC0_HAZARD TLBW ERET
すると...
topが動くのが不思議... pic.twitter.com/mvyoiTJWnb
— lucky owner (@nullnilaki) September 9, 2015
とりあえず、基本panic、運が良ければマルチユーザー移行という段階は 脱して100%マルチユーザー移行出来るようになった が、SIGABRTが頻発してしまう... どこが悪いのだろうか? https://t.co/5s31YspLJ9
— lucky owner (@nullnilaki) September 14, 2015
やったねたえちゃん!
しかし、起動はするものの、SIGABRTが頻発してしまうため、調査を続けることにしました。
そのうち、シルバーウィークがやってきたので、実家に帰る事にしました。
実家ソン! pic.twitter.com/z13ONjDJhL
— lucky owner (@nullnilaki) September 19, 2015
そこで転機がやって来たのです!
そのころには、Miodさん(OpenBSD/sgiのえらい人)とTwitter上でやりとりをしていたので、
メンションもらったついでに、思い切ってパッチを見てもらう事にしました。
この機会を逃すと、また、手元で眠らせてしまう気がしたので...
@MiodVallat This patch will boot up to multi-user mode in exchange for "Abort trap". Crossing fingers, https://t.co/QBqwtooYhn
— lucky owner (@nullnilaki) September 19, 2015
そしたら、あれよあれよという間に...
Thanks to @nullnilaki who spotted my stupid bug, my POWER Indigo 2 system is finally running OpenBSD/sgi multiuser!
— Miod in the Middle (@MiodVallat) September 20, 2015
...and they said R8000 would never get supported by free software. Fools! (-:
— Miod in the Middle (@MiodVallat) September 21, 2015
miod@ modified a couple things: Enable IP26 builds.
— OpenBSD src Changes (@OpenBSD_src) September 20, 2015
OpenBSD/sgiのWebページ、更新されてる... Supported hardwareに IP26 (POWER Indigo2) family: (support completed after the 5.8 release) って書いてある...
— lucky owner (@nullnilaki) September 23, 2015
今まで動かなかった原因は、
が原因でした!
これでOpenBSD/sgiはsgiのマシンに使われていたすべてのMIPS系CPUを制覇した事になります。
何故、自分がこのようなお手伝いを出来たかというと、
R8000が特殊で誰も持っていないという事につきると思います。
実際、Linux/MIPSのページには
"R8000 は現在未サポートです。これはこのプロセッサが一部の SGI の機種のみで使われた
比較的まれなプロセッサで、Linux/MIPS 開発者が誰もこのような機種を持っていない、
ということも理由の一部です。"
と書いてあります。
http://archive.linux.or.jp/JF/JFdocs/MIPS-HOWTO-9.html#ss9.8
また、他のMIPS系のCPUと構成が違うためソースの共有が出来ない部分が多数有り、余計誰も見なかったという事が考えられます。
/src/sys/arch/mips64/mips64/cache_tfp.c
/src/sys/arch/mips64/mips64/cache_tfp_subr.S
/src/sys/arch/mips64/mips64/exception_tfp.S
/src/sys/arch/mips64/mips64/tlb_tfp.S
残念ながら負荷をかけるとSIGBUSやらSIGSEGVやら発生する問題が有るのですが、
おいおい調べていきたいと思います。
@nullnilaki Unfortunately there are still R8000-specific bugs, stressing the system for a few hours causes unexpected SIGBUS or SIGSEGV.
— Miod in the Middle (@MiodVallat) September 26, 2015
まぁ、
@nullnilaki Miodさんが喜んでくれて何よりです (`・ω・´) http://t.co/M2BPfNB836
— lucky owner (@nullnilaki) September 23, 2015
が感想です。(日頃お世話になっているし)
それと、MiodさんにR8000の話を振られた時に、タイミングよくパッチを提出
できた事は大きかったと思います。
タイミング、大事です。
謎の/src/sys/arch/mips64/exception_tfp.Sでやたらと
"2"で引いたり、左シフトしたりしている理由は、
The 2 in the original code is log2(pte size); k0 >> PAGE_SHIFT will be the pte number. But in the page table, it is stored as an array of 32-bit words, so we need to shift it to the left by 2. The original instructions: PTR_SRL k0, PAGE_SHIFT - 2 andi k0, ((NPTEPG / 2) - 1) << 2 are equivalent to: PTR_SRL k0, PAGE_SHIFT andi k0, (NPTEPG / 2) - 1 PTR_SLL k0, 2 and guarantees the address is correctly aligned for the `lwu' instruction later.
だそうでした。
反省点は、10月11月12月とIngressにハマって、まったくマシンいじりを放置していました。
疲れた... pic.twitter.com/GxZ8PudVqw
— lucky owner (@nullnilaki) December 12, 2015
このようなアドバイスを頂いていたのに、@gussunoyoyoさん、すいません...
今日のさいとうさんのL1キャッシュをフラッシュするときにL2キャッシュもフラッシュしているにもかかわらず、SIGBUS or SIGSEGVがおこるならば、コンテキストスイッチするときに、TLBを全部フラッシュして問題の切り分けしてみたら?というアドバイスはためになった
— lucky owner (@nullnilaki) October 3, 2015
よく遊び、よく学べということで!
あしたは、いよいよNetBSD developerのnonakapさんの登場です!
今年もどんな記事を書いてくださるのか、大変楽しみですね!(・∀・)ニヤニヤ
(相変わらず中指を飛ばすコミュニケーション)
おしまい。
えっ
NetBSD Advent Calendarなのに、OpenBSDだって!?
(゚ε゚)キニシナイ!!
それと、R8000関係で最近こんなことがありました。
currentバグッてるぅ (ノシ 'ω')ノシ バンバン https://t.co/pZ4hFHbC4S pic.twitter.com/Dk3XxK55f7
— lucky owner (@nullnilaki) December 18, 2015
どうやら、この変更が原因
'Re: CVS: cvs.openbsd.org: src' - MARC
らしいのですが、
+ * Execution of the `sync' instruction is not supported by the + * T-Bus and raises a machine check exception.
を疑問に思いました。
バスから見てCPUの命令ってどういう風に見えるんでしょうね?
おしえてつついさ〜ん!
参考文献など:
はじめて読む MIPS(リローデッド)
OpenBSD/sgi on octane2 - exception.S・tlbhandler.SにおけるGET_CPU_INFO()とコンテキスト保存、割り込みの話 - かーねる・う゛いえむにっき
謝辞:
いつもtwitterでふぁぼってくださる皆様
なまあたたかい目で見守ってくださるつついさんをはじめとしたNetBSD関係者の方々
追加:
つついさんにきいてみたところ、下記のような回答でした。
@nullnilaki これもMDの話なのでよーわかりませんが、 sync命令 https://t.co/qoCbh9dxUr の仕様上CPUからI/Oに対して何か信号操作をした後Ackを受けるピンがあって、本来ならI/O側が応答するけど、それをサポートしない場合は例外で(文字数
— Izumi Tsutsui (@tsutsuii) 2016, 1月 23
@nullnilaki MIPSだとメモリマップドI/O https://t.co/W5qWUHbjRx なのでCPUからみたらメモリもI/Oも区別はなくて、CPU側に「アクセス完了」の信号入力があって、メモリでもデバイスでもその応答を確認したら次に進む、みたいな感じじゃないかと
— Izumi Tsutsui (@tsutsuii) 2016, 1月 23