config(2)
大掃除
大掃除と掛けて、何と解く? DRAMのリフレッシュ方式の一つと解く。 その心は? まとめて、ドーンとやる、バースト・リフレッシュ。
この他にも、チョロチョロやる、分散リフレッシュとか、 隠れてやるヒディン・リフレッシュがある。これは、外出時に ルンバに掃除させるとか、かな。
大掃除って、日本だけの風習? フェルミ推定してみる。ニュースでは、神社とかお寺の大仏さんの 煤払いってやるから、宗教行事が転じて、一般に広まった? ならば、世界的に行われても不思議ではない。
次は答え合わせ。ググるが楽だけど、それじゃバカになる。 図書館へ行って、知のコンシェルジュである司書に相談かな。 年中行事の本でも調べれば、出てくるかも。
tofu
wslの端末を開くと、豆腐文字に見回れる事が度々発生。ロケールをちゃんと設定してないから だろうと思って、emacsに貼り付けたら、浮かびあがってきた。
Linux 用 Windows サブシステムが Microsoft Store で入手可能になりました。 'wsl.exe --update' を実行するか、https://aka.ms/wslstorepage にアクセスしてアップグレードできます Microsoft Store から WSL をインストールすると、最新の WSL 更新がより速く提供されます。 詳細については、https://aka.ms/wslstoreinfo をご覧ください。
M$自身がリナに擦り寄って、こういう宣伝をするなんて、世の中変ったものだ。
ややこしや、最新WSL2のバージョンは「1.0.0.0」――WSL2をインストールする最新手順も紹介
この方ってWindows屋さんでしょ。注目の的ですよ。
VMware Workstation 16.2.5 Player Release Notes
とか言っていたら、新しい案内が届いた。そろそろ来年の準備をしておけって事だな。
dmassage の例
dmassage -t dmassage -f /bsd | config -e -o /nbsd /bsd dmassage -s GENERIC >SMALLKERNEL
興味が有るのは2番目の例。どうやらdmesgに表れないデバイス情報を取出してるっぽい。そして、その情報を元に新しいカーネル nbsd を作る。configの2番目の用例だな。
どんな情報が出てくるか、ログしてみる。
vbox$ doas dmassage -f /bsd >LOG config: eof
そして、確認。530ヶも不要なデバイスが有るとな。GENERICってのは、そんなに色々なデバイスがサポートされてるのか。さすがi386の世界だな。
disable 0 video* at uvideo*|utvfu* disable 2 midi* at umidi*|sb0|sb*|mpu*|mpu*|autri*|eap*|env disable 3 drm0 at inteldrm*|radeondrm* : disable 529 ipmi0 at mainbus0 disable 530 esm0 at mainbus0 quit
実際に書き換えたカーネルを作ってみる。
vbox# dmassage -f /bsd | config -e -o /tmp/nbsd /bsd OpenBSD 7.2 (GENERIC.MP) #2: Thu Nov 24 23:53:30 MST 2022 root@syspatch-72-i386.openbsd.org:/usr/src/sys/arch/i386/compile/GENERIC.MP Enter 'help' for information ukc> disable 0 video* at uvideo*|utvfu* 0 video* disabled ukc> disable 2 midi* at umidi*|sb0|sb*|mpu*|mpu*|autri*|eap*|env 2 midi* disabled : ukc> disable 530 esm0 at mainbus0 530 esm0 disabled ukc> quit Saving modified kernel.
そして、差分を確認。カーネルのサイズには変更は無い。だからデバイス探索のスイッチがOFFになってるんだね。これで、余分な手間が省けるから、起動が速くなるって寸法だな。
vbox# cmp -l /bsd /tmp/nbsd 13220543 2 4 13220607 2 4 : 13237407 2 4 13237503 0 3
real kernel conf
dmassageの用例に、-f /bsdなんてのがある。バイナリーファイルであるカーネルをperlが扱えるのか? そんな疑問が芽生えたぞ。しゃーない、perl言語と対面するか。
# Globals. my $GETCONF = "/bin/echo 'lines 1000\nlist' | /usr/sbin/config -e"; my $DMESG = "/var/run/dmesg.boot";
こんなのが宣言されてた。ならば、それを撫ぞってやろう。
riscv# config -e -o /tmp/xx /bsd OpenBSD 7.2 (SEEING) #3: Fri Nov 18 16:30:39 JST 2022 sakae@riscv.my.domain:/sys/arch/riscv64/compile/SEEING Enter 'help' for information ukc> help help Command help list add dev Add a device base 8|10|16 Base on large numbers change devno|dev Change device disable attr val|devno|dev Disable device enable attr val|devno|dev Enable device find devno|dev Find device list List configuration lines count # of lines per page show [attr [val]] Show attribute exit Exit, without saving changes quit Quit, saving current changes nkmempg [number] Show/change NKMEMPAGES
ふむ、途中で止らないようにページサイズを1000行にしておいてからlistするんだな。こういうインターフェースが用意されているとは、今迄configを扱っていて重大な見落としだな。
ukc> lines 1000 ukc> list 0 vscsi0 at root flags 0x0 1 softraid0 at root flags 0x0 2 mainbus0 at root flags 0x0 3 cpu0 at mainbus0 early -1 flags 0x0 : 109 hotplug count 1 (pseudo device) 110 wsmux count 2 (pseudo device)
ハードなデバイスとソフトな仮想デバイスの現在の状況を教えてくれるんだな。じゃ、ちょっと実験で、ホットプラグってデバイスを無効にしてみる。
ukc> disable 109 109 hotplug disabled ukc> list : 109 hotplug count 1 disable (pseudo device) 110 wsmux count 2 (pseudo device)
ちゃんとdisableになった。これだけ分れば、あえてperl語を解析する必要は無いだろう。
実際に最小デバイスのカーネルを作って起動してみたけど、圧倒的に時間を食ているのは、/etc/rcの実行部分だったよ。体感スピードで効いてくるのは、カーネルのコンパイル時だけそうだ。
mkheaders()
前回の積み残しであったconfigの追求。何が対象になるかと調べたら、ずっと前の方でファイルリストを作っていた。
(gdb) b addfile if flags != 0 Breakpoint 1 at 0x9be2: file files.c, line 94. (gdb) r -b /tmp/K -s /sys SEEING Starting program: /tmp/config -b /tmp/K -s /sys SEEING (gdb) bt #0 addfile (nvpath=0x797afd20, optx=0x797b5020, flags=4, rule=0x0) at files.c:94 #1 0x19c5a1a6 in yyparse () at gram.y:177 #2 0x19c5c710 in main (argc=1, argv=0xcf7efc98) at main.c:267 (gdb) up #1 0x19c5a1a6 in yyparse () at gram.y:177 177 XFILE pathnames fopts fflgs rule { addfile($2, $3, $4, $5); };
難解なやつが出てきた。少しmanを当って、書き方のルールを調べてみる。
file.conf(5)
needs-flag Create an attribute header file, defining whether or not this attribute is compiled in. needs-count Create an attribute header file, defining how many instances of this attribute are to be compiled in. This rule is mostly used for pseudo-devices.
対象を探してみる。
vbox$ cd /sys/dev vbox$ find . -name 'files.*' | xargs grep needs ./acpi/files.acpi:file dev/acpi/acpi.c acpi needs-flag ./acpi/files.acpi:file dev/acpi/acpicpu.c acpicpu needs-flag :
こういうやつを選び出しているんだな。最初にがfileで始まる、それが$1。続いてファイル名($2)、次がfopt($3)、そしてfflgs($4)、次がルールとな。こういう風にaddfileの引数を組み立てているんか。
下記は、一例
(gdb) p *fi $9 = { fi_next = 0x0, fi_srcfile = 0x797b5760 "/sys/conf/files", fi_srcline = 100, fi_flags = 4 '\004', fi_lastc = 0 '\000', fi_nvpath = 0x797afd20, fi_base = 0x797bcf40 "drm_drv", fi_optx = 0x797b5020, fi_optf = 0x0, fi_mkrule = 0x0 } (gdb) p *fi.fi_nvpath $10 = { nv_next = 0x0, nv_name = 0x797b3ee0 "dev/pci/drm/drm_drv.c", : }
mkioconf()
次は、見落とししてたけど、大事そうなやつ。
唯一ダイナミックに作成されるCのソースファイル。動き出したカーネルがこのソースで定義された情報を参照して、ドライバーの設定を変更するのに使われる。ざっと見てみたけど、FreeBSDには無い機能だ。
何故って、そんな機能は、モジュールシシテムが実現しちゃっているから(Linuxも同様だ)。でも、これって、モジュールはカーネルの外側に有るんで、セキュリティー的な弱点になる。それを嫌ってOpenBSDは、モジュール方式を止めた。その変わりにカーネルが許す範囲で、機能をON/OFF出来るようにした。4.1BSDで登場して、4.4BSDで更新されたって事だ。
mkioconf(void) { qsort(packed, npacked, sizeof *packed, cforder); if ((fp = fopen("ioconf.c", "w")) == NULL) { : v = emithdr(fp); if (v != 0 || emitexterns(fp) || emitloc(fp) || emitlocnames(fp) || emitpv(fp) || emitcfdata(fp) || emitroots(fp) || emitpseudo(fp)) {
例の失敗しない限り、実行してくって方式で、長くなるコードを適当に分解してる。
ここに到達する前に作られ整理された情報はpackedに入っている。例えばあるドライバーは複数の親で使えるって言うような情報を上手く表現するとかだ。packed.cに詳しい説明が有るけど、日曜プログラマーには、ちと荷が重いので省略する。
config -e
カーネルのconfigを変更してみる。主対象はドライバー類のON/OFFとかだ。取り上げるのはお馴染の金魚時計。金魚は中国原産ってチコちゃんでやってたね。農林水産省は、錦鯉の輸出を頑張るそうだからね。
riscv$ gdb config (gdb) r -e -o /tmp/X bsd ukc> find gfrtc 48 gfrtc* at syscon*|simplebus*|mainbus0 early 0 flags 0x0 ukc> disable 48 Breakpoint 1, disable (devno=48) at ukcutil.c:609 609 int done = 0; (gdb) bt #0 disable (devno=48) at ukcutil.c:609 #1 0x0000000b100c3ba8 in Xdisable (cmd=0x3ffffc5210) at cmd.c:137 #2 0x0000000b100c3214 in config () at ukcutil.c:1348 #3 0x0000000b100bed30 in ukc (file=0x3ffffc6998 "bsd", outfile=0x0, uflag=0, force=0) at ukc.c:161 #4 0x0000000b100b1cf2 in main (argc=1, argv=0x3ffffc6858) at main.c:220 613 cd = get_cfdata(devno); (gdb) p *cd $1 = { cf_attach = 0xffffffc000677190, cf_driver = 0xffffffc00080d038, cf_unit = 0, cf_fstate = 2, cf_loc = 0xffffffc00080b510, cf_flags = 0, cf_parents = 0xffffffc00080b4be, cf_locnames = 1, cf_starunit1 = 0 } (gdb) 615 switch (cd->cf_fstate) { (gdb) 620 cd->cf_fstate = FSTATE_DSTAR; (gdb) 621 break; (gdb) p cd.cf_fstate $2 = 4 :
ほー、 cf_fstate
が、スイッチになるのか。
autoconf
何気に autoconf(9) なんてやってみたら、下記のような集合が出てきた。/usr/share/man/man9には、確かにautoconfと言う原稿が置いてあるんで、親切心の発露かな。
NAME config_search, config_rootsearch, config_found_sm, config_found, config_rootfound - autoconfiguration framework
config_search
で、どこから呼び出されるか確認しる。
(gdb) bt #0 config_search (fn=<optimized out>, parent=0xffffffc002da4000, aux=<optimized out>) at /usr/src/sys/kern/subr_autoconf.c:1\ 88 #1 0xffffffc0002e6a80 in config_found_sm (parent=0xffffffc002da4000, aux=0xffffffc000805c80, print=0x0, submatch=0xffffffc00\ 03646b0 <mainbus_match_primary>) at /usr/src/sys/kern/subr_autoconf.c:321 #2 0xffffffc000364964 in mainbus_attach_node (self=0xffffffc002da4000, node=1004, submatch=0xffffffc0003646b0 <mainbus_match\ _primary>) at /usr/src/sys/arch/riscv64/dev/mainbus.c:254 #3 0xffffffc000364602 in mainbus_attach_cpus (self=0xffffffc002da4000, match=0xffffffc0003646b0 <mainbus_match_primary>) at \ /usr/src/sys/arch/riscv64/dev/mainbus.c:314 #4 0xffffffc0003643fc in mainbus_attach (parent=<optimized out>, self=<optimized out>, aux=<optimized out>) at /usr/src/sys/\ arch/riscv64/dev/mainbus.c:126 #5 0xffffffc0002e6c9a in config_attach (parent=0x0, match=<optimized out>, aux=0x0, print=0x0) at /usr/src/sys/kern/subr_aut\ oconf.c:412 #6 0xffffffc0002e6e48 in config_rootfound (rootname=0xffffffc000623abc "mainbus", aux=0x0) at /usr/src/sys/kern/subr_autocon\ f.c:337 #7 0xffffffc00038e096 in cpu_configure () at /usr/src/sys/arch/riscv64/riscv64/autoconf.c:53 #8 0xffffffc00030adb4 in main (framep=<optimized out>) at /usr/src/sys/kern/init_main.c:336
次は、 gfrtc_match
で、金魚時計を発見して、それを取り入れる部分。
(gdb) bt 4 #0 gfrtc_match (parent=<optimized out>, match=<optimized out>, aux=0xffffffc000805c80) at /usr/src/sys/dev/fdt/gfrtc.c:96 #1 0xffffffc0002e661a in mapply (m=0xffffffc000805bb8, cf=0xffffffc00080bfa0 <cfdata+2688>) at /usr/src/sys/kern/subr_autoco\ nf.c:147 #2 0xffffffc0002e64ee in config_search (fn=<optimized out>, parent=0xffffffc002da4000, aux=<optimized out>) at /usr/src/sys/\ kern/subr_autoconf.c:216 #3 0xffffffc0002e6a80 in config_found_sm (parent=0xffffffc002da4000, aux=0xffffffc000805c80, print=0x0, submatch=0xffffffc00\ 2da4000) at /usr/src/sys/kern/subr_autoconf.c:321 (More stack frames follow...)
kern/subr_autoconf.c
に面白い関数が有って、ON/OFF を参照してた。
(gdb) bt #0 mapply (m=0xffffffc000805ec8, cf=0xffffffc00080b590 <cfdata+112>) at /usr/src/sys/kern/subr_autoconf.c:132 #1 0xffffffc0002e6e32 in config_rootsearch (fn=<error reading variable: Cannot access memory at address 0x0>, aux=0x0, rootn\ ame=<optimized out>) at /usr/src/sys/kern/subr_autoconf.c:300 #2 config_rootfound (rootname=0xffffffc000623abc "mainbus", aux=0x0) at /usr/src/sys/kern/subr_autoconf.c:336 #3 0xffffffc00038e096 in cpu_configure () at /usr/src/sys/arch/riscv64/riscv64/autoconf.c:53 #4 0xffffffc00030adb4 in main (framep=<optimized out>) at /usr/src/sys/kern/init_main.c:336
呼ばれた時の状況例。
132 if (m->indirect) 1: *m = { fn = 0xffffffc00029ccba <simplebus_submatch>, parent = 0xffffffc002da5000, match = 0x0, aux = 0xffffffc000805b98, indirect = 0, pri = 0 }