boot
この新しいNotePCを2カ月使ってきた訳だけど、突然画面がブラックアウトして、1-2秒後に 回復するって症状が目立つようになった。その時は、PCがハングしてる雰囲気。
何か、イベントログに上がっていないか調べてみた。 昨日は、早朝に2時間、午後に3時間ぐらい使っていたんだけど、午後に15回ぐらい、
ディスプレイ ドライバー igfx が応答を停止しましたが、正常に回復しました。 イベントID 4101
ってのが、出ていた。発生日時とログの時間が一致してるんで、これに間違い無いだろう。 でも、何で午後だけ? それは病気だからです。人間様の病気みたいだな。午前中は 調子いいんだけど、午後はメタメタになるとか。(調子の良い日も有る)
まてまて、こういうのは、その時何をやってたかにも関係するだろう。朝は、犬猫の町内 巡回宜しく、ネットの巡回。午後は、VMWAREでBSDを動かし、emacsでメモを取ってた。 こういう、食い合わせの問題?
食い合わせと言えば、数日前、女房が夕食後に本物のcoreを吐いた。オイラーの手持ちの 分析器では分析不可能。想像するに、色々きのこの炒め物に毒きのこでも紛れていたか、烏賊の黄金和えに やられたか? ちゃんと、霧島産の芋焼酎で消毒したはずだけどな。お湯割りだったので消毒効果が薄かったか。同じ物を食べたオイラーは全く 問題なく、原因不明。
ネットに聞いてみると、あるわあるわ。みんなこういう症状に悩まされていたのね。 オイラーだけじゃなくて、一安心しましたよ。
解決方法の筆頭は、ディスプレードライバーを更新してみれ、でした。後は、どうも 民間療法ぽいので、症状悪化の可能性が有るんで無視。ドライバーの更新だけしとこう。
どうやるんだ。ドライバー一覧は7機時代はコンパネからアクセス出来たんだけど、10機に なって、転機が訪れたようで、そこには無かった。
ウィンドウ管理ツールの中のコンピュータの管理がそれだった。管理ツールを立ち上げ、 左側にあるメニューからデバイスマネージャーを選ぶ。中央にデバイスリストが出てくる。 そこから、ディスプレーアダプターを選ぶ。
ドライバーのタグをクリックすると、2015/10/28付けのドライバーだった。新しいのが 出ているだろうと思って、更新。インテルさんの所まで、自動的に取りに行って、 新しいのになった。HD Graphics 520 2016/07/01 版。 これで暫く使ってみよう。
ついでに、わんさか溜まっているイベントログをクリアしておこう。どうやるんだと 調べたら、みんなGUIの奴隷なのね。それぞれのイベントを選んで、ログのクリアを 実行、、、、ってのを、永遠に繰り返すみたい。 そんなの、コンピュータにやらせろ。
@echo off REM バッチファイルの実行時刻を取得する setlocal enabledelayedexpansion set EXEC_DATE=%date:~-10,4%%date:~-5,2%%date:~-2,2% set EXEC_TIME=%time: =0% set EXEC_TIME=%EXEC_TIME:~0,2%%EXEC_TIME:~3,2%%EXEC_TIME:~6,2% REM 一時ファイル用のパスを作成する set EVENTLOG_LIST=%~dp0\eventlog_%EXEC_DATE%%EXEC_TIME%.list if exist %EVENTLOG_LIST% ( del %EVENTLOG_LIST% ) REM 全てのイベントログの名前をファイルに出力する wevtutil el > %EVENTLOG_LIST% if not "%ERRORLEVEL%" == "0" ( echo ERROR: Failed to get event list : %EVENTLOG_LIST% exit /b 1 ) REM ファイルを参照して、イベントログをクリアする for /f "delims=" %%a in (%EVENTLOG_LIST%) do ( wevtutil cl "%%a" if not "%ERRORLEVEL%" == "0" ( echo ERROR: Failed to clear event log : "%%a" if exist %EVENTLOG_LIST% ( del %EVENTLOG_LIST% ) exit /b 1 ) ) REM 一時ファイルを削除する if exist %EVENTLOG_LIST% ( del %EVENTLOG_LIST% )
これを、管理者権限のターミナルから実行すると、きれいさっぱりと証拠隠滅が 出来るぞ。
boot messages
前回だかのCUIな端末をコンソールにする設定で起動すると、(若し、VGAなコンソールが 見えるとすると)下記のようなメッセージが流れている。
Booting from Hard disk... Using drive 0, partition 3. Loading...... probing: pc0 com0 mem[639k 190M a20=on] disk: fd0 hd0+ >> OpenBSD/amd64 BOOT 3.31 switching console to com0
そして、下記は、CUIな端末をコンソールと認識した状態の冒頭部分。
[ob: ~]$ cu -l /dev/ttyp4 Connected to /dev/ttyp4 (speed 9600) booting hd0a:/bsd: 9718712+2331680+287752+0+663552 [72+806784+513799]=0xdaa950 entry point at 0x1001000 [7205c766, 34000004, 24448b12, fbe0a304] [ using 1321296 bytes of bsd ELF symbol table ] Copyright (c) 1982, 1986, 1989, 1991, 1993 The Regents of the University of California. All rights reserved. Copyright (c) 1995-2016 OpenBSD. All rights reserved. http://www.OpenBSD.org :
普段お目にかかれないメッセージをキャプチャー出来て、プチ嬉しかったりします。
所に、上記のメッセージは何処で出しているの?
Booting from
[ob: sys]$ find . -name '*.[ch]' | xargs fgrep 'Booting from' ./arch/amd64/stand/libsa/cmd_i386.c: printf("Booting from %s ", cmd.argv[1]);
このファイルを見ると、Xboot(void)に定義がされていた。boot_amd64(8)あたりの説明かな。
と、このままコードを追って行ってもつまらないので、上記のman繋がりで攻めてみるか。
installboot
が、関連に出てた。PCに電源が入ってカーネルが動き出すまでには、カーネルがメモリーに ロードされなければならない。但し、カーネルはOSが地均ししたHDDの中。そこから、カーネル を見つけ出して、ロードしてくれるのが、bootの役目。
だから、このbootプログラムは別名でローダーとも呼ばれる。カーネルとは独立した プログラム。PC/ATの仕様では、DISKの一番先頭(MBRと呼ばれる)に、超簡単なプログラムを 置き、その力を借りてbiosbootを読み込んで、それを動かして複雑なbootプログラムを読み込むと言う2段構えになってる。
OSをインストールする時、この一連のbootプログラムをHDDに配置する事になる。その配置を やってくれるのが、installbootって言う、まんまの名前のコマンドだ。
nオプションを付ける事で、dry run 出来るそうなので、やってみた。
# installboot -nv wd0 Using / as root would install bootstrap on /dev/rwd0c using first-stage /usr/mdec/biosboot, second-stage /usr/mdec/boot would copy /usr/mdec/boot to /boot /boot is 5 blocks x 16384 bytes fs block shift 2; part offset 64; inode block 40, offset 2216 master boot record (MBR) at sector 0 partition 3: type 0xA6 offset 64 size 2624768 /usr/mdec/biosboot will be written at sector 64
/usr/mdecも見ておけって事なんで、見ておく。
[ob: mdec]$ ls -l total 952 -r-xr-xr-x 1 root bin 97280 Jul 27 03:49 BOOTIA32.EFI* -r-xr-xr-x 1 root bin 107008 Jul 27 03:49 BOOTX64.EFI* -r-xr-xr-x 1 root bin 1403 Jul 27 03:49 biosboot* -r-xr-xr-x 1 root bin 70980 Jul 27 03:49 boot* -rw-r--r-- 1 root bin 72384 Jul 27 03:49 cdboot -rw-r--r-- 1 root bin 2048 Jul 27 03:49 cdbr -r-xr-xr-x 1 root bin 44800 Jul 27 03:49 fdboot* -r-xr-xr-x 1 root bin 512 Jul 27 03:49 mbr* -rw-r--r-- 1 root bin 82316 Jul 27 03:49 pxeboot
サフィックスがEFIとなってるのは、ウィンテルの陰謀に対応するbootプログラムだな。 後は、biosbootとbootの組み合わせ、もしくはcdbrとcdbootの組み合わせ。pxebootは ネットワーク上にあるカーネルをbootする仕組みかな。他には、fddからのブートも 対応してる。何処かのリナみたいに古い物は切り捨て御免じゃないね。
mbrも一応載ってる。これもinstallbootの一環で転送されるんだろうね。 強引に確認してみるかな。
[ob: tmp]$ dd if=/dev/wd0c of=mbrP count=1 1+0 records in 1+0 records out 512 bytes transferred in 0.000 secs (560175 bytes/sec) [ob: tmp]$ strings mbrP !Using drive X, partition Y MBR on floppy or old BIOS Read error No O/S No active partition
今使ってるDISKの先頭1セクターをファイルに落とした。そして、そこに含まれる 文字列を拾い出してみた。お次は、/usr/mdecに有るやつ。
[ob: mdec]$ strings mbr !Using drive X, partition Y MBR on floppy or old BIOS Read error No O/S No active partition
一致したって事ですかね。いや、若干の違いが有るなあ。どうも違いはテーブルエリア っぽいぞ。
[ob: mdec]$ cmp -l mbr /tmp/mbrP 496 0 1 497 1 2 500 377 376 503 0 100 507 377 350 508 377 325 510 177 1
実際に、installbootのコードを見たけど、mbrは書き込んでいないっぽい。他の ツールを使った時にでも書き込まれるのかな。fdisk(8)か。
boot
ついでに、bootの持ってる文字列も眺めておく。
[ob: mdec]$ strings boot : 3.31 probing disk BIOS %s:%s cannot open %s: %s >> OpenBSD/amd64 %s %s /etc/boot.conf boot> /etc/random.seed booting %s: /bsd : entry point at 0x%lx [%x, %x, %x, %x]
ブートメッセージに含まれている文字列が、ぞろぞろ居たぞ。そして、これらのboot 関係者は、i386のモードで動いているな。readelfしたら、そう書いてあったぞ。
@ install CD
保存してたインストール用のCDが有るので、cd-bootの構成を覗いておく。 boot.confが有って、bsd.rdを指定しているな。
[ob: seed]$ sudo vnconfig vnd0 install60.iso [ob: seed]$ sudo mount /dev/vnd0c /mnt [ob: seed]$ cat /mnt/etc/boot.conf set image /6.0/amd64/bsd.rd [ob: seed]$ ls /mnt/6.0/amd64/ INSTALL.amd64 boot.catalog* cdboot man60.tgz xshare60.tgz SHA256 bsd* cdbr xbase60.tgz TRANS.TBL bsd.mp* comp60.tgz xfont60.tgz base60.tgz bsd.rd* game60.tgz xserv60.tgz [ob: seed]$ sudo umount /mnt [ob: seed]$ sudo vnconfig -u vnd0
cdからのブート用に、cdbrとcdbootが用意されてるね。TRANS.TBLは、いにしえのDOSの 短い名前を長い名前に変換するための表だな。
そして、要のbsd.rdが居るな。これがインストール時に動くminiなカーネル兼ちっちゃい ファイルシステムを内蔵したものか。
で、このbsd.rdはどうやって作るの?
bsd.rd
arch/conf/RAMDISK_CD あたりが、その仕様書だな。全体は、/usr/src/distrib/ あたりか。 ここでmakeすればいいんだな。
インストール時に使われるスクリプトは、/usr/src/distrib/miniroot の中。注目は、 install.subか。
dot.profileが、メインで、install.subが文字通りサブだ。いやメインだ。dot.profileは install.subをbootするスクリプトと言った方が妥当と思われ。
以下、install.subの最後の部分。
case $MODE in install) do_install;; upgrade) do_upgrade;; esac
後は、インストールの手順を思い出しながら追っていけ。
コンパイルしてみる。
boot計がどうやってコンパイルされるか調べてみる。主戦場は、/sys/arch/amd64/stand/の下。 standってのは、standaloneを省略したんだな。カーネルから独立してる。けど、微妙に 密接してるんで、一応systemなソースの扱い。 mbrの例
# make sh /usr/src/sys/arch/amd64/stand/mbr/../../../../kern/genassym.sh cc -Os -Wall -Werror -fno-stack-protector -DMDRANDOM -I/usr/src/sys/arch/amd64/stand/mbr/../../../.. -I/usr/src/sys/arch/amd64/stand/mbr/../libsa -I. -I/usr/src/sys/arch/amd64/stand/mbr < /usr/src/sys/arch/amd64/stand/mbr/../etc/genassym.cf > assym.h.tmp && mv -f assym.h.tmp assym.h cc -m32 -I/usr/src/sys/arch/amd64/stand/mbr -I/usr/src/sys/arch/amd64/stand/mbr/../../.. -fno-pie -I/usr/src/sys/arch/amd64/stand/mbr/../../../.. -I/usr/src/sys/arch/amd64/stand/mbr/../libsa -I. -I/usr/src/sys/arch/amd64/stand/mbr -c mbr.S ld -nostdlib -Ttext 0 -x -N -s -Bstatic -e start -nopie -melf_i386 -L/usr/libdata -o mbr mbr.o text data bss dec hex 512 0 0 512 200
biosbootの例
# make sh /usr/src/sys/arch/amd64/stand/biosboot/../../../../kern/genassym.sh cc -Os -Wall -Werror -fno-stack-protector -DMDRANDOM -DLOADADDR=0x40000 -DLINKADDR=0x40120 -DBOOTMAGIC=0xc001d00d -I/usr/src/sys/arch/amd64/stand/biosboot/../../../.. -I/usr/src/sys/arch/amd64/stand/biosboot/../libsa -I. -I/usr/src/sys/arch/amd64/stand/biosboot < /usr/src/sys/arch/amd64/stand/biosboot/../etc/genassym.cf > assym.h.tmp && mv -f assym.h.tmp assym.h cc -m32 -fno-pie -DLOADADDR=0x40000 -DLINKADDR=0x40120 -DBOOTMAGIC=0xc001d00d -I/usr/src/sys/arch/amd64/stand/biosboot/../../../.. -I/usr/src/sys/arch/amd64/stand/biosboot/../libsa -I. -I/usr/src/sys/arch/amd64/stand/biosboot -c biosboot.S ld -nostdlib -Ttext 0 -N -x -Bstatic -nopie -melf_i386 -L/usr/libdata -o biosboot biosboot.o text data bss dec hex 512 0 0 512 200
bootの例
: ld -nostdlib -Bstatic -Ttext 0x40120 -N -x -nopie -melf_i386 -L/usr/libdata -o boot.new srt0.o conf.o boot.o bootarg.o cmd.o vars.o gidt.o random_i386.o cmd_i386.o dev_i386.o exec_i386.o gateA20.o machdep.o bioscons.o biosdev.o diskprobe.o memprobe.o time.o softraid.o alloc.o ctime.o exit.o getchar.o memcmp.o memcpy.o memset.o printf.o putchar.o snprintf.o strcmp.o strerror.o strlen.o strncmp.o strncpy.o strtol.o strtoll.o close.o closeall.o cons.o cread.o dev.o disklabel.o dkcksum.o fstat.o lseek.o open.o read.o readdir.o stat.o elf32.o elf64.o loadfile.o ufs.o aes_xts.o explicit_bzero.o hmac_sha1.o pbkdf2.o rijndael.o sha1.o divdi3.o moddi3.o qdivrem.o strlcpy.o adler32.o crc32.o inflate.o inftrees.o text data bss dec hex 70130 284 7664 78078 130fe
bootの冒頭部分は省略しちゃったけど、biosbootのそれみたいに、技巧的な事が行われていた。ちゃんと解析してみよう。これって、Makefileの解析にもなるな。
次に知りたいのは、どうやって bsd.rd を作っているかって事。以前の調べだと、ramdisk用の小さいカーネルに、miniなファイルシステムを合体させてあるはずなんだけど。
インストールに関わる事なんで、systemの所に有るかと思ったら、一般ソースの部類に 属してた。/usr/src/distの下に、ソース一式が置いてある。インストール用cdの作成やら、 そのコンテンツの作成やらが出来る。
今回は、bsd.rdなんで、当たりを付けて、/usr/src/distrib/amd64/ramdisk_cdです。 で、Makefileを見るととっても複雑。ええい面倒だ。rootになって走らせちゃえ。
まてまてと言う声が聞こえます。そんなの dry run(実行した積りモード) さ。
[ob: ramdisk_cd]$ make -n awk -f /usr/src/distrib/amd64/ramdisk_cd/../../miniroot/makeconf.awk CBIN=instbi n /usr/src/distrib/amd64/ramdisk_cd/../common/list /usr/src/distrib/amd64/ramdis k_cd/list.local > instbin.conf crunchgen -E -D /usr/src -L /usr/lib -c instbin.c -e instbin -m instbin.mk inst bin.conf : make -f instbin.mk SRCLIBDIR=/usr/src/distrib/amd64/ramdisk_cd/../../../lib all strip -R .comment instbin dd if=/dev/zero of=/var/tmp/image.211 bs=512 count=4480 vnconfig -v -c vnd0 /var/tmp/image.211 disklabel -w vnd0 rdroot newfs -m 0 -o space -i 4096 /dev/rvnd0a fsck /dev/rvnd0a mount /dev/vnd0a /mnt mtree -def /usr/src/distrib/amd64/ramdisk_cd/../../miniroot/mtree.conf -p /mnt/ -u : umount /mnt vnconfig -u vnd0 cp /var/tmp/image.211 mr.fs
ちょっと省いちゃったけど、インストールに必要なコマンド類が収集されて、それがinstbinに まとめられて、所定の位置に鎮座。最後に、mr.fsって名前になる。
cp /usr/src/distrib/amd64/ramdisk_cd/../../../sys/arch/amd64/compile/RAMDISK_CD/ bsd bsd cc -o rdsetroot /usr/src/distrib/amd64/ramdisk_cd/../../common/elfrdsetroot.c /usr/src/distrib/amd64/ramdisk_cd/../../common/elf32.c /usr/src/distrib/amd64/r amdisk_cd/../../common/elf64.c cp bsd bsd.rd /usr/src/distrib/amd64/ramdisk_cd/rdsetroot bsd.rd mr.fs cp bsd.rd bsd.strip strip bsd.strip strip -R .comment bsd.strip gzip -c9n bsd.strip > bsd.gz
今度はカーネルをコンパイルし、bsd.rdを作る。それと先ほど作ったmr.fsを合体するための rdsetrootプログラムをつくり、それを利用して、合体。最後に圧縮しとく。これで、疑問は 氷解したけど、続きを見ておく。miniroot60.fsの作り方。
dd if=/dev/zero of=/var/tmp/image.211 bs=512 count=7936 vnconfig -v -c vnd0 /var/tmp/image.211 fdisk -yi -l 7936 -b 960 -f /usr/mdec/mbr vnd0 disklabel -wAT /usr/src/distrib/amd64/ramdisk_cd/template vnd0 newfs -t msdos /dev/rvnd0i mount /dev/vnd0i /mnt mkdir -p /mnt/efi/boot cp /usr/mdec/BOOTX64.EFI /usr/mdec/BOOTIA32.EFI /mnt/efi/boot umount /mnt newfs -m 0 -o space -i 524288 -c 7936 /dev/rvnd0a mount /dev/vnd0a /mnt cp /usr/mdec/boot /usr/src/distrib/amd64/ramdisk_cd/boot strip /usr/src/distrib/amd64/ramdisk_cd/boot strip -R .comment /usr/src/distrib/amd64/ramdisk_cd/boot installboot -v -r /mnt /dev/rvnd0c /usr/mdec/biosboot /usr/src/distrib/amd64/ra mdisk_cd/boot dd if=bsd.gz of=/mnt/bsd bs=512 : cp /var/tmp/image.211 miniroot60.fs
fdiskを使ってmbrを書き込み。dos領域を作ってウィンテルの陰謀に対応させ。installbootで 昔堅気のbootに対応させ、最後に、カーネルとファイルシステムが一緒になったものを コピーするとな。長い道のりだな。