tsutsuiの作業記録置き場

NetBSDとかPC-6001とかの作業記録のうち、Twitterの140字では収まらない内容や記事としてまとめるべき内容をとりあえず置いてみる予定

NetBSDコミットログで振り返る2021年

かつては「自宅から車で行けるOSCには出る」という方針でイベント駆動で NetBSD謎マシン展示をしていたのですが、2020年1月のOSC大阪を最後に物理OSC開催がなくなってしまい、2021年はついに一度もOSCその他のNetBSDマシン展示発表をしない年になってしまいました。10月以降はmikutterにどっぷりでしたが

じゃあ昨年はNetBSD的に何をやっていたのか、ということで、 NetBSD CVSリポジトリのコミットログメッセージが流れてくる source-changes の mailing list の情報をベースに、2021年のNetBSD活動を振り返ってみようと思います。

2021年のコミット数

source-changes の mailing list はそのままでは集計や検索がしづらいので、 NetBSD developer の ryo@ さんがメンテしている NetBSD Source-Changes commit log search から情報を拾ってみると、2021年に自分のコミット数は 86回 でした。

これが多いのか少ないのかと考えると少なくはないのでしょうが、2020年は NetBSD/sun3 の Xorg サーバー実装とか MIPS Windows NTマシン Express5800/230 の電源修理からの NetBSD/arc 復活とか フランスから送られてきた HP9000/300 フレームバッファXサーバー用ビットマップオペレーション実装とか自分的に満足度の高い作業をやっていた反動で、2021年はなんとなく地味に感じてしまっていたのでした。いろいろやってるのにそれを展示してないからなおさらか

とはいえ、改めて 2021年の自分のコミットを見ていると、それなりに力を入れて書いたものもあります。そういうものをいくつかピックアップしてみました。

NetBSD/x68k Xサーバー 3ボタンマウスエミュレーション

まず 2021年2月7日コミットのこれ。

X68030の純正マウスは2ボタンなのですが、過去に自分が X11R7対応したXサーバーでは真ん中ボタンのいわゆる3ボタンエミュレーション(左右ボタン同時押しで中ボタンが押された扱いになる)が実装されていませんでした。

これ自体はだいぶ前から気になっていたのですが、2020年秋ごろからサーベイ自体はしていて、「各Xサーバー共通で使える3ボタンエミュレーション実装はない」ということはわかっていました。実態としては、旧XFree86ベースのxf86-input-mouseドライバLinux evdev用ドライバWindows Xサーバー実装の Xwin それぞれで別の実装がされている状態でした。

それぞれがまた歴史が積み重なった実装で読むのが大変なのですが、最終的には状態遷移をきっちり設計してあるっぽい xf86-input-mouse のマウスドライバ実装の状態遷移部分を他のインターフェースから分離する形で持ってきて、 NetBSD/x68k に限らずなるべく汎用な形で流用ができるインタフェース設計と「読めばわかる」構造体その他の実装定義を考えた上で NetBSD/x68k サーバーに組み込んだ形でコミットしました。

「左右同時押しで中ボタン扱い」という要件自体は簡単なように見えるのですが、「同時押しといってもどれだけのズレを許容するのか」「同時押しを待っている間に離されたらどうするのか」「同時押しの後に片方だけ離したらどうするのか」「中ボタンのダブルクリックは可能なのか」と言ったことを考え出すと結構難しい設計が求められます。

また、マウスのイベント自体も、PS/2やバスマウス、各種ワークステーションで定義が異なる、OSのデバイスドライバごとでも定義が異なる、Xサーバー側プロトコルも明示的なドキュメントがない、という混沌状態で、「コードから定義を推測する」という練習にもよいかと思いました。

なお、最初は X68030 エミュレータである XM6i 上でテストをしたところまったく意図通りに動かず調べるのに苦労したのですが、「ホストである NetBSD/i386 側の Xサーバーでも 3ボタンエミュレーションが有効になっているため先にそちらにイベントを取られてしまっている」というしょうもない罠にハマりました。3ボタンエミュレーションを無効にするには /etc/X11/xorg.conf のマウス以外の各セクションをすべて書く必要があり、これも結構面倒でした……。

NetBSD/m68k カーネルスタックオーバーフロー問題修正

次に結構苦労したのが、この 2021年2月23日の NetBSD/m68k カーネル全般のスタックリークの修正。

前述の 2020年の NetBSD/sun3用 X11R7サーバーを動かしていると「おもむろにカーネルスタックオーバーフローっぽい症状で panicする」という現象が起きていました。

ただ、カーネルスタックが壊れているためにバックトレースが取れないという問題がありました。カーネルスタックを2倍以上に増やしても発生するため「単なるスタック不足ではない」ということは見えていたのですが、そもそも「スタックがリークする」という現象がどういうシナリオで起こり得るのかがずっとわからないままでした。

その後、 NetBSD/x68k の3ボタンマウス修正に伴うカーネルクラッシュダンプ修正の作業を経て、前項の NetBSD/x68kサーバーでも起きていたカーネルハングアップの現象が NetBSD/sun3 のスタックオーバーフローと同じ現象らしい、ということがわかってきました。

XM6i上でも再現するということがわかったので、ひたすら頭悪く実行トレースを取るという手法で調査を進めました。

MC68030マニュアルや各種実装と突き合わせた結果、「シグナルハンドラ関連でコンテキストを切り替える際に m68kのトラップ要因によってはカーネルスタックをずらす必要があるがその処理が抜けている」らしい、という仮説にたどり着きました。

このあたりのツイートを拾い出すとエンドレス Togetter セルフまとめになるので詳細はまた別途

確信には至らない状態でバグレポとして投げたところ、 NetBSD開発者の thorpej氏からも「その修正で妥当」というコメントもいただくことができました。

こうやって結果が見えてくると理屈もわかるのですが、メモリフォールトのトラップがトリガであるため「メモリが極端に少ないマシン」で「激しくページアウトするような負荷をかけた場合」にしか起きないこともあり、結果としてこのバグは10年以上も残ったままになっていたのでした。今でも m68kマシンを「使っている」ような人はたいてい MC68060でメモリフル実装だったりする

いずれにせよ、これで X68030 や sun3/60での Xサーバー展示デモにおける「そもそもXを起動すると落ちる」という問題が一つ解消したはずなので、早く物理OSCが復活してほしいところです。

なお「目スタックトレース」という作業は一部の方には異様なものとして映った模様。慣れればそんなに大変じゃないんですけどね

HP9000/300 HP-IBディスクサポート改善

これはカーネルの改善というよりは実ハードウェアのテスト作業がメインでした。

HP-IBというよりも GP-IB あるいは IEEE 488 といったほうが通じやすいかと思いますが、もともとは HPが自社計測機用に作ったバスプロトコルおよび物理層の規格が HP-IBです。計測機用規格といいつつ、パソコン用にディスクドライブやプリンタなども接続可能で、 NetBSD/hp300 でもそれらのデバイスのサポートが入っています。

私自身は 2001年頃に NetBSD/hp300 を動かし始めてからいろいろあって今では NetBSD/hp300 の機種担当という立場にあるのですが、 2020年まで一度も HP-IBのデバイスNetBSD/hp300でテストしたことがないまま、という状況でした。

HPDrive

機種担当であるにも関わらず HP-IBの動作がずっと未確認というのはよろしくないなと思っていて HP-IB関連情報を過去にサーベイした際に、Windows PC + HP-IBインターフェースの組み合わせで HP-IBバイスを模擬する HPDrive というのものを見つけていました。

www.hp9845.net

この HPDriveで使える National Instruments製 PCI GP-IBインターフェースボードがヤフオクで手頃な値段で出ているのを見かけたのが 2020年の年末。

その後の GP-IB用ケーブル手配その他を経て、無事に NetBSD/hp300 で動作確認できたというの以下の 2021年1月9日のツイート。

とはいえ、このときは「何もしなくても動いた」という状態だったので、特にこれといったコミットはありませんでした。

HPDisk

HP-IB関連サーベイの中では、前述の HPDrive の他に「PICマイコンとSDカードで HP-IBディスクを模擬する」という HPDisk というものも見つけていました。

www.dalton.ax

別PC設定というひと手間が必要な HPDriveと違い実デバイスと同じようにつなぐだけで使えるこちらもいいなと思ってはいたのですが、配線基板を起こす、もしくは入手する手間を考えると「すぐに試してみる」というわけにも行かず、いったん保留にしていたのでした。

そんな過去経緯のあと 2021年4月上旬になって、この HPDiskの作者の方から「HPDiskのテストのために HP9000/340 に入れた NetBSD/hp300 が起動しないのだけれど」という相談を受けました。この起動問題自体についてはざっと調べて「古いモノクロフレームバッファの probeルーチンで存在しないカラーパレットをアクセスしているため」という既知の問題が放置されていただけというのがわかり、修正して無事に起動するようになりました。

このやり取りの中で「自分でハンダ付け工作できるなら基板送るよ」と言われて「ぜひぜひ」とお願いして部品発注その他を経て作り出したのが 2021年5月。

じわじわ始まっていた半導体需要逼迫の影響で PICマイコンの手配に手間取りましたが、PICライタも入手して動かし始めたのが5月連休明けくらい。

これも個別作業のツイート引用をしだすと終わらなくなるので詳細は別の機会に回しますが、「NetBSD/hp300ほど HP-IBプロトコルを強烈に使う testsuit はない」というコメントをもらう状況で、こちらからデバッグログを送っては更新版の Firmwareを送ってもらう、ということを10回近く繰り返すこととなりました。

最終的には 2021年7月8日の Firmware v0.20で NetBSD/hp300 でも HPDisk の一通りの機能が動くようになりました。この作業の中で、従来の NetBSD/hp300で正しくサポートされていなかった「複数スレーブデバイスディスクのサポート」についても HPDisk側で任意のドライブを指定できるように改善してもらったため、別途教えてもらっていた OpenBSD/hp300 の修正も合わせて持ってくることにしました。

コミット内容としては微妙に地味だったりするのですが、上述のように NetBSD/hp300に対する問い合わせがきっかけで久しぶりにハードウェア工作をしたり実機デバッグをしたりという交流を含めて楽しく作業をさせてもらいました。

なお、HPDiskの作者の方にもこの更新の件を取り上げていただいていますのでこちらもどうぞ。

www.elektormagazine.com

LUNAキーボードのCAP/かなLEDおよびブザーコマンドサポート

最後は9月から10月にかけて作業したこれら OMRON LUNAの NetBSD/luna68k キーボードドライバ関連のコミットです。

マイナーすぎるにもほどがある と言われそうですが、きっかけは LUNAエミュレータnonoの作者の一人である @moveccr さんのこのレポート。

LUNAキーボード マウスON/OFFコマンド

この問題を説明しだすとまた記事が長くなってしまうのですが、ざっと書くと
「LUNAのキーボードとマウスは同じシリアル通信ラインで信号が送られる」
「マウス信号のデータはキーボード送信データ 0x00〜0xFF のバイトデータのうち 0x80〜0x87 のデータをヘッダマークとして使ってボタン情報と移動量情報を送る」
NetBSD/luna68kカーネルはコンフィグでマウスが無効だとマウスデータの処理を行わない」
の3つを合わせると
「(マウスを使わない)ブートローダーとマウス無効のカーネルでマウスを動かすとマウスデータをキーデータと誤認する」
という問題です。

LUNAキーボードの仕様については過去に仕様書を見てざっと把握していたので「そう言われればそうだよな」と思いつつ実機でテストしてみたのですが、どうも再現しません。

この原因は
「LUNAのキーボードにはマウスON/OFFコマンドがある」
「実キーボードは起動時にマウスON状態の仕様だが、LUNA実機のROMは起動後にマウスOFFコマンドを送っている」
NetBSD/luna68kのカーネルも起動時にマウスOFFコマンドを送っていて /dev/wsmouseopen(2) するときにマウスONコマンドを送っている」
エミュレータであるnonoではマウスON/OFFコマンドが未実装」
ということでした。

ただ、実機でも起動後にキーボードを抜き差しした場合は同じ現象が再現します。

というわけでこの修正をしたのが冒頭のコミット5件のうち最初のもの。

CAP/かなLEDコマンドとブザーコマンド

この「マウスON/OFFコマンド」の修正と見出しの「キーボードのCAP/かなLEDおよびブザーコマンド」に何の関係があるかというと、「LUNA本体→キーボードにシリアルデータとしてコマンドを送信する」という処理の部分です。

この問題が持ち上がった 2021年9月時点の NetBSD/luna68kカーネルでは、LUNAのキーボードの仕様として定義されている機能のうち、キーボードLEDコマンドの制御とブザーコマンドの制御については未実装で、マウスON/OFFコマンドのみが暫定に近い形で実装されているのみでした。

マウスON/OFFのコマンドの実装としては「カーネルが起動時にマウスOFF」「デバイスの open 時にマウスON、 close時にマウスOFF」「同時にオープンできるデバイスは1つのみ」というものだったので、同時に複数のコマンド送信要求が発生することはありません。このため、マウスON/OFFのコマンドはシリアル通信ICのuPD7201のレジスタを調停無しで直接アクセスする実装になっていました。

マウスコマンド以外のLEDコマンドやブザーコマンドはユーザーランドプロセスからの入力をトリガにシステムコールで呼ばれる場合があります。また、CAPキー入力とブザー出力とが同時に発生するケースもあるため、これらを適切に処理するためには「デバイスドライバ側で送信データキューを用意してソフトウェア割り込み等を用いて送信キューデータを順次送信する」といった実装が必要になります。

この送信キュー処理については NetBSD/sgimips の R3000系マシンの実装を参考にサクッと(?)記述しました。

wscons(4) の LED・ブザー実装

詳細実装以前のインターフェース設計の問題として、NetBSDの MI (Machine Independent つまり各機種共通仕様) のスクリーン+キーボードのコンソールドライバである wscons(4) の仕様として、キーボードLEDのON/OFFやブザー出力要求がどのような経路でデバイスドライバまで到達するのかも調べる必要がありました。

調査においては、もともと wscons の仕様を説明した文書がほとんどないこと、LEDやブザーをキーボード側にコマンドとして送信する機種(主に NetBSD/alpha, NetBSD/pmax, NetBSD/sparc, NetBSD/sgimips といった Sun, DEC, SGIといったワークステーション)でドライバをちゃんと実装したものがほぼなかったことから NetBSDsrc/sys/dev/wscons および各機種のコードをかなり読み込むハメになりました。

またセルフまとめ状態で長くなってしまいますが、調査の過程についてはTwitterで適当にメモっていたのでそのまま引用します。

とりあえずでユーザーランドプロセスからの要求に対しては以下のように対処すれば良いということはわかったのでこれで実装。

  • CapsLockその他のLEDについては、デバイス固有の処理として WSKBDIO_SETLEDS (と WSKBDIO_GETLEDS) の ioctl(2) だけを実装すれば良い (それより上位は wscons(4) 側で対処される)
  • ブザーについては、デバイス固有の処理として WSKBDIO_COMPLEXBELL の ioctl(2) だけを実装すれば良い (それ以外は wscons(4) 側で対処される)

この修正が冒頭の5コミットのうち2つ目の修正。

LUNAキーボード CAP/かなキー挙動対応

前項のLED調査の過程で LUNAの CAPキー および かなキー の動作は
「キーを押してLEDが点灯するときに PRESSイベントを送信」
「キーを押してLEDが消灯するときにRELEASEイベントを送信」
「キーを離したときはイベントを送信しない」
という「いにしえのメカニカルロックキーをエミュレーション(?)した動作」であることが改めて確認されました。PS/2やUSBではこれらの modifier キーについても物理イベントは他のキーと共通(なのでドライバレベルでの入れ替えも可能)

NetBSD/luna68k カーネルではこれに対応しておらず CAPキーの操作とLED状態とCapsLock状態が一致しないという問題があったため、今回合わせて修正しました。これが3つ目のコミット。

また、nonoのキーボードエミュレーション実装の挙動が実機と異なるようだったので報告。これは nonoさんの次のバージョンで修正されることになりました。

uPD7201 sio(4) ドライバ整理

このあたりの uPD7201シリアルドライバの実装を見ていると、過去から気になっていた記述が思い出されて気になってしまいました。せっかくだから、と過去経緯を含めて調べて「コードを読めば何をしているかわかる」という方向にすべくいろいろ調査した上で見直しを検討。

このあたりを整理してコミットしたのが4つ目のコミット。

カーネルメッセージ出力とコンソールドライバ実装

この uPD7201ドライバの整理と並行して考える必要があったのが「ユーザーランドプロセスだけではなく、カーネル内 printf(9) によるコンソール処理についてもLEDとブザーの処理が必要」という部分。

シリアルコンソールの場合、 LEDの処理はなく、ブザーについても単にブザーに相当する ASCII制御コードを送信するだけです。よってカーネル側 printf(9) についても特別な処理はなく、 cnputc(9) 相当の関数でデータを送信しているだけです。

一方、キーボードコンソールの場合は LED制御もブザー吹鳴もキーボード側にコマンドを送信する必要があるものの、一般的にカーネル printf(9) からの呼び出しでは割り込みが使えません。よって、ユーザーランド側処理と同様の送信キューによる実装では対応が難しいという問題があります。

真面目に実装しようとすると、ストレージデバイスのように「割り込み使用不可の場合のポーリング処理実装」を入れる必要がありますが、超マイナー機種、かつ、使用頻度が高いとは言えないキーボードの 1〜3バイトのコマンドのためだけにどこまで工数をかけるのか、というのが悩みどころでした。

このあたりも細かく説明すると終わらないので、セルフまとめツイートで雰囲気だけ感じてもらえればと思います。

やはり無駄に長い引用になってしまう

最終的な妥協案としては、既存の cnpollc(9) の仕組みを使ってカーネル cngetc(9) からの呼び出しかどうかを判定した上で、カーネル内 cngetc(9) の場合は送信キューを使わずに従来のマウスON/OFFコマンド同様に直接 uPD7201のレジスタを操作してコマンドを送信する実装としました。

これが最後の5つ目のコミット。

まとめ

こうやって改めて思い出してみると、それぞれの作業で結構頭を使って考えていたのかな、とは思わないでもないですね。

「OSCがなくなったのでイベント駆動がなくなったと言いながらこれらの作業はどうなんだ」と言われてしまいそうですが、x68k Xサーバーの3ボタンエミュレーションを除くと「ユーザーの見た目にはほとんど現れないが内部的なあるべきハードウェア対応実装設計およびインターフェース設計」という感じで、このたぐいの「詳細実装設計メインの面白さ」をOSCネタで表現できたかというと微妙です。どんなもんでしょう

2022年以降もOSC含めた世情がどうなっていくのか見えていませんが、これまでと同じようなペースでぼちぼち NetBSDをいじっていけたらなあ、と思っています。今回のエントリで書いた内容に限らず「こんな中身の話を聞いてみたい!」というご意見があれば聞かせていただけると幸いです。