NetBSD私的年次報告2021

このところ、本業が多忙で作業できてない私ことrin@です。

モチベ向上のために、Advent Calendarを利用して、 2020年12月〜2021年11月の思い出深い事件をまとめてみます。

お前の自分語りなんぞ興味ねーわ、 というツッコミが聞こえてきますが、 過疎ってるし、まあええやろ!

さすがに最終日は憚られたので、 24日までに間に合わせようとしたら意外と大変で、 リンクとか貼ってない手抜き版です。 詳細はnervのコミットログとか見てね: 本体, pkgsrc。 言い訳ばかりで面目ない!

2020年12月

evbarm/ラズパイ0-3でbig-endian modeをサポート

ラズパイ2-3はearmv7{,hf}ebで、 ラズパイ3はaarch64ebで動くはずだったが、 mailbox, DMAC, early console等にlittle endian依存が残っていた。

ラズパイ0-1のearmv6{,hf}ebは、 Nのカーネルが動作した実績がなかった。

v6{,hf}ebのABIはv5{,hf}eb以前と互換性のあるBE32を想定していたが、 v7{,hf}eb以降と互換性のあるBE8に切り替えた。

N以外の人はfirmwareがlittle endianで動いてるマシンを わざわざbig-endian modeで使ったりしないので、 バイトオーダの切り替え方法はろくに解説されていない。 ARMv6でlittle-endian modeからBE8 modeに切り替えるには、 まずSCTLRのUビットを立ててから、 setend beする必要があった。

2021年1月

powerpc/bookeのpmap_procwr()を直す

pmap_procwr()はnoopでも大抵のものは動いてしまうので、 まず壊れてる・まじめにテストされていないと思うのが吉。

2021年2月

amiga/boot(8)でFFSv2をサポート

基本的にはlibsaの枠組みで簡単にできた。 first-stage bootはself-relocationするのが少し面白かった。

2021年3月

evbppc/Explora 451を直す

IBM403の割り込みハンドラを書き直したら、 NetBSD 6以来、 長らく壊れていたのが動くようになった。 その後、wsfb(4) Xサーバなどもサポートした。

powerpc/booke, ibm4xxでptrace(2)をサポート

booke, ibm4xxにはoeaのMSR DEビットがない。 実はoeaよりはるかに高機能なHWデバッグ機構があるのだが、 どちらかと言えばfirmware/OS向けで、ptrace(2)には応用しづらい。 そこで、software breakpointを埋め込む方式に切り替えた。

radeonfb(4)でmlterm-fbをサポート

WSDISPLAY_[GS]ETCMAP ioctl(2)が壊れていた。 Xサーバはハードウェアレジスタを直接いじるので、 動いているように見えていたのだった。 似たような理由でmlterm-fbが動かないドライバはまだありそう。

mac68k/DJMEMCMAXを直す

Quadra 800で驚異の実メモリ520MBが実現した。 680[46]0のpmapはしょぼいので、直さなきゃ。

sandpoint/玄箱HGのtftp bootを直す

libsaのネットワークコードの闇を見た。 mbufを使っていないので、 リニアバッファのポインタをデクリメントして、 ヘッダを追加していくのだった。 邪悪!

2021年4月

evbppc/DHT Walnut 405GP評価ボードのサポート

PCIスロットを2本搭載した可愛い評価ボード。 NがSoCをサポートしていたので、 PCIの割り込みルーティングとか書いてやるだけで動いた。

405関係のコードは整理したけど、まだ汚いなぁ。 DTB?

ページサイズが16KBなので(?)、nvme(4)が動かない。

powerpc/ibm4xxのpmap_{enter,kenter_pa}(9)を直す

UVM_KMF_NOWAITを指定せずにuvm_km_alloc(9)を呼んでいたため、 実メモリが足りないときにデッドロックしていた。

PMAP_CANFAILのときは、ENOMEMを返せばUVMが良きに計らってくれる。 そうでなければご愁傷様だが、仕方ない?

GCC10/powerpcのregressionを直す

upstreamが4xxとbookeのサポートを壊していた。 誰も使ってない証拠。

2021年5月

ixg(4)をalphaで動かすお手伝い

F由来のコードはm_free(9)してからbus_dmamap_unload(9)する場合が多いが、 N/alpha等のbus_dmaでは逆にしないと動かなかった。

QEMU/m68kのQuadra 800モードでNetBSDを動かすお手伝い

QEMUの中の人の質問に答えつつ、 細々とした修正をコミットする簡単なお仕事。 QEMU側の修正もコミットされたっぽい。

aarch64のCOMPAT_NETBSD32関係のお掃除

VFPを使うコードが正常に動くようになるなど。 ↓の問題との切り分けができて助かった。

libunwind/armを直す

GCCとLLVMではDWARFでのVFPレジスタの取り扱いに違いがあり、 前者がサポートできていなかった。 その結果、VFPを使うコードがC++の例外を投げた瞬間、 libunwind内の不整合でプロセスが死んでいた。 GCCのバージョンが上がる毎に、整数演算にVFPを使う最適化が進行して、 どいひー度合いが増していたのだった。

perl v.s. tmpfs on COMPAT_NETBSD32問題が直る

COMPAT_NETBSD32かつ作業ディレクトリがtmpfsという条件で、 lang/perl5がビルドできないという謎現象。 Nのino_tは64ビットで、 なおかつLP64カーネルのtmpfsでは上位32ビットがnon-zeroになる都合上、 miniperlにlong longサポートが入っていないと動かないところまで突き止めた。

perlの中の人たちと議論したところ、 inode numberがホストの整数型に収まらない場合は文字列として格納することで、 64-bit safeにしたつもりが、いくつかのモジュールで文字列から整数に再変換して 比較していたことが発覚、修正。

2021年6月

armのFPEでカーネルが落ちるバグを直す

ARMv7以降はデフォルトでFPEを上げてこないので、誰も気づいていなかった。 これもどいひーなバグ。

aarch64ebのGDBを直す

実はaarch64でも壊れていたが、 little endianなのでたまたま動いているように見えた。 多様性、重要。

GCC10/armのregressionを直す

GCC10にNetBSD EABIサポートをupstreamしたときに、 ヘッダのインクルード順を間違えてエンバグしていた。

compiler-rt/armのEABIHF規約違反を直す

earmv[67]hfで複素数型を使うと落ちるという、 これまたどいひーなバグ修正をupstreamから取り込む。

KERNEL_LOCK()がMODULAR && !MULTIPROCESSORで壊れてたのを直す

MODULAR && !MULTIPROCESSORなカーネルで KERNEL_LOCK()はnoopになっていたが、 モジュール側では有効化されていて、 不整合が生じていた。

誰も!MULTIPROCESSORなカーネルなんか使っていないという証拠。

compiler-rt/armのEABI規約違反を直す

arm EABIではspは8バイト境界に整列している必要があるが、 compiler-rtの一部のルーチンが違反していた。

ARMv5teの{ld,st}rd命令は、 オペランドが8バイト境界に整列している必要があるため、 GCCがspのアラインメントを仮定した最適化をすると、 あちこちでalignment faultが発生することになる (↓のGCC/alphaの項を参照)。

ARMv6以降はunaligned accessが可能になったため、 誰も気づかなかった模様。

evbarm/HDL-GのKERNEL_BASEを直す

KERNEL_BASEのデフォルトが0xc0000000から0x80000000に 変更されたときに直すのを忘れていたため、 カーネルテキストとして+1GB余分にマップしようとして pmap_bootstrap()で落ちていた。

2021年7月

alphaのGCC最適化問題、ついに解決

NetBSD 9.0のリリース直前、alphaで新しいjemallocが動かない問題が発覚。 がんばって二分法で探索して、最適化抑制で対処した。 んだけど、その後もいろんなコードが-O2で動かず、気持ち悪かった。

devel/gettext-toolsで発生した問題を詳しく解析したところ、 GCCはspが16バイト境界にアラインしているつもりで最適化していたが、 Nのカーネル・ユーザランドは8バイト境界のアラインメントしか保証していなかった。

alphaにはSystem V (ELF) ABIが存在しないので、 どちらが正しいと言うことでもないが、 パフォーマンスを考慮した結果、16バイト境界にアラインすることになった。

最近のGCCはこの手の最適化を積極的にやってくれる。 私の知る限り、Nではpowerpc, m68k, alpha, armv5が影響を被っている。

sh3のcpu_switchto()を直す

この時期、sh3のカーネルは相当不安定で、 full ATFすらおぼつかないような状況だった (現在は1個だけKASSERTを無効化しておけば、 DIAGNOSTICカーネルが問題なく動く)。

sh3ではコンテキストスイッチのときに、 SRレジスタを待避・復元するのだけれど、 SRには割り込みマスクが含まれている。 古いコードはこの部分まで復元していたので、 禁止していたはずの割り込みがいつの間にか許可されて、 めちゃくちゃになっていたのだった。

2021年8月

XScale i80321のsplraise(9)を直す

古いarmは割り込みまわりのコードが共通化されていないので、 けっこうカオスである。 XScale i80321には、 splraise(9)でIPLを下げることができるバグがあり、 これまた禁止したはずの割り込みが(以下同文)。

evbarm/玄箱PROでbig-endian modeをサポートする

ラズパイのところで書いたとおり、 firmwareがlittle-endian modeで走り始めたarmプロセッサを、 big-endian modeに切り替える方法はほとんど黒魔術である。

玄箱PROのARM926EJ-Sの場合は、 SCTLRのBビットを立てる、 nop 3連発でプリフェッチバッファを空にする、 という操作をlittle endianでコーディングした後、 big endianでSCTLRを空読みするコードを書いてやれば、 後はbig-endian modeで動作する。 これでearmv5ebのテスト環境が手に入った。

ちなみに、HDL-Gのi80321では同じ方法が使えず、 big-endian modeで動かせていない。 どうしたものやら。

2021年9月

sh3のpmapのバグが直る

pmap_enter(9)がENOMEMを返すパスが間違っていたため、 pmap_page_protect(9)が無限ループに陥る場合があった。

LP64BEだけで顕在化するcurses(3)のバグを直す

どういうわけかaarch64ebとsparc64だけで失敗するテストがあり、 調べてみたところ、curses(3)が画面の書き換えを検出するために内部に 持っているhashの計算が間違っていた。 バグったアルゴリズムで計算した値がlittle endianと ILP32BEでたまたま一致していたので、LP64BEが壊れているように見えたのだった。 多様性、(以下同文)。

sh3のfault handlerを直す

sh3マシンに負荷をかけると、 どういうわけかpc = 0番地でクラッシュする場合があった。 MDの関数ポインタがNULLになってる場所を一生懸命探したが見つからず、 あれこれコードを読んでいたら、例外ハンドラが間違っていて、 pcb_onfaultがNULLの場合もpcに上書きしていた。

COMPAT_LINUXでfstatat64(AT_EMPTY_PATH)の雑サポート

Fedora 34というかglibc 2.33のrtldがfstatat64(2) のAT_EMPTY_PATHを使うために、 ダイナミックリンクライブラリを見つけられなくなっていた。 どうしてfstat(2)じゃダメなんですか、とかいろいろ意味不明だけど、 とりあえず雑サポートを追加。

2021年10月

wdc(4) at pcmcia(4)のmemory-mapped modeを直す

PCMCIAやそのsubsetであるCFは、 ATAレジスタをI/O空間にマップできるほか、 古いPCMCIAの拡張メモリと同じスタイルでメモリマップすることもできる。 両者はpinoutが一部異なっていて、memory-mapped modeでは (原則として)割り込み線が使えず、ポーリング駆動が必要になる。

F, O, LはそもそもPCMCIA ATAのmemory-mapped modeなんて、 ハナからサポートしていないわけだが、 Jornadaやペルソナで使われているSoCである HD64461では、2つのPCMCIAスロットのうち一方は memory-mapped mode専用で、I/O-mappedはサポートしていないため、 Nでは必要になるケースもあるわけだ。

世の中の大半のATAコントローラは割り込み駆動なこともあり、 NCQサポートを追加したときにポーリング対応がエンバグしていた。

sh3のPCMCIA HWバグ対応を直す

↑でも登場したHD64461というか、sh3コアのPCMCIA機能にはバグがあり、 16-bit wordの読み書きに続いて、byte単位の読み書きをすると、 誤って16-bit word全体がbyte-enabledになるという問題がある。 のだが、ウェブ上で探した限り、このバグについての文書が見つけられなかった。

↑のwdc(4)の問題を調べるために買った別冊インターフェース TECH I 14号のコラムで、このバグの詳細が解説されていた。 それに倣ってコードを修正したところ、 今まで動かなかったep(4) at pcmcia(4)が元気に動くようになった。

2021年11月

aarch64ebだけで顕在化するstrict aliasing規約違反を直す

どういうわけかaarch64ebだけで失敗するtest caseがあり、 よくよく調べてみたところ、一種のstrict aliasing規約違反を発見した。 2種類の異なるポインタが指す実体を、 (ポインタを割り当てる前に) 構造体代入でコピーするのは、 少なくともGCCにとっては許しがたい行為のようだ。

MDの最適化やバイトオーダの都合上、 たまたまaarch64ebだけで顕在化していた。 多様性。

hpcarmのDDB btを直す

armのDDBはAPCSスタックフレームを前提としているので、 -mapcs-frameしないとback traceがとれないのだった。

おしまい

今年はまあまあがんばったかな? そうでもないかな? 来年もよろしくお願いいたします。