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したら、そう書いてあったぞ。

Boot処理

OpenBSD FAQ - Disk Setup

@ 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

後は、インストールの手順を思い出しながら追っていけ。

OpenBSD/Install53

OpenBSD を PxeBoot でインストール

コンパイルしてみる。

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に対応させ、最後に、カーネルとファイルシステムが一緒になったものを コピーするとな。長い道のりだな。

etc

IPv6通信の仕組みを完全理解 シンプルなネットワーク構成が可能に