ママー。NetBSDのRAMDISK Kernelの/dev/consoleはどこから来るの?という話
この記事は
NetBSD Advent Calendar 2016 - Qiita 24日目の記事です。
すいません、ておくれました。26日目ということにしてください...
N君がある日RS/6000にNetBSD/ofppcをインストールしようとすると奇妙な事が起こりました。
ふむ...
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
NetBSD/ofppc pic.twitter.com/IoxNpV6keI
/dev/consoleが無いというエラーが出てだんまりしています...
調べてみたところ、エラーを出力しているのは
https://nxr.netbsd.org/xref/src/sys/kern/init_main.c#870
のようです。
どういうことなのでしょう?
@tsutsuiiさんにアドバイスを頂きました!
@nullnilaki カーネルは自前でコンソールのデバイスに出力しますが、 /sbin/init その他のユーザーランドバイナリは /dev/console のデバイスノード経由でカーネルの中にアクセスする、という感じです
— Izumi Tsutsui (@tsutsuii) 2015年1月2日
つまりユーザーランド側から/sbin/initが/dev/consoleを開いて文字の読み書きを始めようにも、/dev/consoleが無いのでカーネルが警告を出しているわけですね。
そこで疑問になるのが、RAMDISK Kernelの/dev/consoleはどうやって作っているのだろうか?という事です。
これについても@tsutsuiiさんにアドバイスを頂きました。
@nullnilaki 2パターンあって
— Izumi Tsutsui (@tsutsuii) 2016年10月26日
・/dev 以下のノードは makefs(8) の -F の spec ファイルで定義
・spec ファイルは src/distrib/common/Makefile.makedev で作成
・MAKEDEVTARGETS は MD Makefile で定義
@nullnilaki もう一つは
— Izumi Tsutsui (@tsutsuii) 2016年10月26日
/dev/MAKEDEV だけが存在して /dev/console がない場合、 init(8) が自力で /dev 以下を mfs でマウントして /dev/console その他を自分で作る
というパターンhttps://t.co/gR279e18Nl
なるほど!/dev/consoleが出来るパターンには2パターンあるようです。
というわけで、早速調べてみました!
例えば、NetBSD/i386をCDからbootさせて、/devを見てみると...
NetBSD/i386 pic.twitter.com/EeJSDNqiBo
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
とMAKEDEVスクリプトがあります。
また、iso-imageをマウントして中身を見てみると、MAKEDEVスクリプトがあります。
NetBSD/i386 pic.twitter.com/YmjNFRZoLq
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
では、別のポートとしてNetBSD/alphaをCDからbootさせて、/devを見てみると...
NetBSD/alpha pic.twitter.com/DfxwY20BZk
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
今度はMAKEDEVスクリプトがありません。
つまり、
★NetBSD/i386は"init(8) が自力で /dev 以下を mfs でマウントして /dev/console その他を自分で作る"パターン
★NetBSD/alphaは"makefs(8) -Fのspec ファイルで定義されたデバイスファイルをファイルシステムイメージとして持っている"パターン
になるわけですね。
/sbin/initでMAKEDEVスクリプトから/dev/consoleを作っているところは
https://nxr.netbsd.org/xref/src/sbin/init/init.c?r=1.107#1647
です。
試しに下記のmakefileをいじって、-DMFS_DEV_IF_NO_CONSOLEを外してやれば、
Cross Reference: /src/sbin/init/Makefile
/sbin/initが/dev/consoleを作ることが出来ないので、下記の様になるわけです。
NetBSD/i386 pic.twitter.com/Zie8IEYgsA
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
では、このMAKEDEVスクリプトはどこから来ているのでしょうか?
試しに
Cross Reference: /src/etc/MAKEDEV.tmpl
の
mkdev console c %cons_chr% 0 600
をコメントしてみると、
initが死んだ? pic.twitter.com/wUYHXujNXX
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
のように
warning : no /dev/console
のエラーが出ています。
また、iso-imageをマウントしてMAKEDEVの中身を見てみると、
mkdev console c %cons_chr% 0 600
がコメントしてあります。
NetBSD/i386 pic.twitter.com/YYhIMofIZt
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
(右枠がソース、左枠がiso-imageのMAKEDEV)
また、NetBSD/alphaも同じように
warning : no /dev/console
のエラーが出ています。
NetBSD/alpha pic.twitter.com/np79N6cb3N
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
つまり、
"init(8) が自力で /dev 以下を mfs でマウントして /dev/console その他を自分で作る"パターンでも
"makefs(8) -Fのspec ファイルで定義されたデバイスファイルをファイルシステムイメージとして持っている"パターンでも
元ネタは
/src/etc/MAKEDEV.tmpl
だということがわかります。
では、どこで/dev/MAKEDEVスクリプトを作っているのかというと、
NetBSD/i386の場合は、
Cross Reference: /src/distrib/common/Makefile.makedev
になります。
NetBSD/alphaの場合は、/dev/以下をどこで作っているのかというと
Cross Reference: /src/distrib/common/Makefile.makedev
になります。
NetBSD/alphaの場合、
Cross Reference: /src/distrib/alpha/instkernel/ramdisk/Makefile
の
MAKEDEVTARGETS= minimal
が
Cross Reference: /src/etc/etc.alpha/MAKEDEV.conf
で定義されていて、
makedev std bpf
のstdが
Cross Reference: /src/etc/MAKEDEV.tmpl
MAKEDEV.tmplのstdで定義されています。
したがって、NetBSD/ofppcの場合、下記のようなパッチを作れば...
gist.github.com
ほら
NetBSD/ofppc pic.twitter.com/5zYBCpx8TS
— Lucky owner/capturer (@nullnilaki) 2016年12月25日
warning : no /dev/consoleが出なくなりました〜
でもこの記事は片手落ちです。
続きはお正月休みにでも書こうと思います。