Boot Manager (boot0)
OpenBSDでも、freebsd-update相当のシステムパッチを当てられるそうなので、やってみた。 まずは、下記のようにパッチの取得元を登録する。(最初から有ればいいのにね)
# cat /etc/installurl #https://ftp.openbsd.org/pub/OpenBSD #https://mirrors.sonic.net/pub/OpenBSD https://cloudflare.cdn.openbsd.org/pub/OpenBSD
次は、どんなパッチを当てられるか(提供されてるか)-cオプションで確認する。有名なメルトダウンも対象になってたぞ。
# syspatch -c 001_tcb_invalid 002_fktrace 003_mpls 004_libssl 005_ahopts 006_prevhdr 007_etherip 008_unbound 009_meltdown # syspatch Get/Verify syspatch62-001_tcb_inv... 100% |*************| 465 KB 00:00 Installing patch 001_tcb_invalid Get/Verify syspatch62-002_fktrace... 100% |*************| 785 KB 00:00 Installing patch 002_fktrace Get/Verify syspatch62-003_mpls.tgz 100% |***************| 837 KB 00:00 Installing patch 003_mpls Get/Verify syspatch62-004_libssl.tgz 100% |*************| 2515 KB 00:00 Installing patch 004_libssl Get/Verify syspatch62-005_ahopts.tgz 100% |*************| 703 KB 00:00 Installing patch 005_ahopts Get/Verify syspatch62-006_prevhdr... 100% |*************| 783 KB 00:00 Installing patch 006_prevhdr Get/Verify syspatch62-007_etherip... 100% |*************| 1030 KB 00:00 Installing patch 007_etherip Get/Verify syspatch62-008_unbound... 100% |*************| 1294 KB 00:00 Installing patch 008_unbound Get/Verify syspatch62-009_meltdow... 100% |*************| 40344 KB 00:07 Installing patch 009_meltdown Relinking to create unique kernel... done.
引数無しでコマンドを実行すると、有無を言わさず全部適用。危険な穴を塞ぐのが目的なので、当然の処置と思うぞ。
# ls -l /var/syspatch/ total 36 drwxr-xr-x 2 root bin 512 Mar 12 06:55 62-001_tcb_invalid drwxr-xr-x 2 root bin 512 Mar 12 06:55 62-002_fktrace drwxr-xr-x 2 root bin 512 Mar 12 06:55 62-003_mpls drwxr-xr-x 2 root bin 512 Mar 12 06:55 62-004_libssl drwxr-xr-x 2 root bin 512 Mar 12 06:55 62-005_ahopts drwxr-xr-x 2 root bin 512 Mar 12 06:55 62-006_prevhdr drwxr-xr-x 2 root bin 512 Mar 12 06:55 62-007_etherip drwxr-xr-x 2 root bin 512 Mar 12 06:55 62-008_unbound drwxr-xr-x 2 root bin 512 Mar 12 06:56 62-009_meltdown s -l /var/syspatch/62-001_tcb_invalid/ < total 612 -r--r--r-- 1 root bin 1292 Oct 12 16:37 001_tcb_invalid.patch.sig -rw-r--r-- 1 root wheel 294544 Mar 12 06:55 rollback.tgz
ログと言うか資料が残ってる。これが有るので、不具合が有ったら元に戻す事が出来るとな。
i386なマシンに入れてるOpenBSDで試したら、メルトダウンは対象外だった。投機に走るような不純な石じゃないわけね。いや、セレロンと言う貧乏人専用な石だから、投機も何も。。。(以下略)
too small kernel
前回、カーネルを適当にダイエットさせた。もう少し頑張れば更に痩せられると思って、チャレンジしてみた。で、その結果。
f51# nm /boot/kernel/kernel | wc 11441 34323 352222
Genericの時は、21728だったから、1万個の名前(変数名や関数名)が削減された事になる。
deb9:tmp$ ls -lh kernel* -rw-r--r-- 1 sakae sakae 2.4M Mar 13 06:51 kernel -rw-r--r-- 1 sakae sakae 16M Mar 13 06:51 kernel.debug
そして、5.3Mだったのが、完全に半分以下になった。もっと古いOSを使うと、フロッピー1枚に OSを押し込む事が出来るかな。フロッピー1枚でルーターを作るとかいうのを見た覚えがあるぞ。
どこをどうしたら、こうなったかは、巻末にconfigファイルを残しておくよ。
boot0
例のムック本を頭から読み始めた。最初はMBRの話である。OSをインストールする時に、ブート・マネージャをMBRに入れるとしたやつだ。リナで言うと、LILOとかgurbに相当する。
アセンブラしかも16Bit版しか出てこない。出鼻をくじく仕組みになってる。今回は頑張って、アセンブラを乗り越えてみる積り。(辛抱出来るかな?)
説明の中で、やたらと boot0cfgが出てくるので、マニュアルを参照してみた。 gasらしいので、資料もね。
use gdb
実際にboot0のコードをgdbで追ってみる。 初っ端からステップ実行してくとBIOSの中のコードを見せられてしまうので、有名な0x7c00に BPを置いてから継続するのが吉。
(gdb) target remote localhost:1234 Remote debugging using localhost:1234 0x0000fff0 in ?? () (gdb) b *0x7c00 Breakpoint 1 at 0x7c00 (gdb) c Continuing. Breakpoint 1, 0x00007c00 in ?? () (gdb) si 0x00007c01 in ?? () (gdb) display/i $pc 1: x/i $pc => 0x7c01: xor %eax,%eax (gdb) si 1: x/i $pc => 0x7c03: mov %eax,%es 0x00007c03 in ?? () 1: x/i $pc => 0x7c03: mov %eax,%es
そして、闇夜のカラスにならないように、次に実行する命令を逆アセンブルさせるのが吉。
=> 0x7c14: rep movsl %ds:(%esi),%es:(%edi) (gdb) p/x $cx $1 = 0xfe (gdb) si 256 1: x/i $pc => 0x7c1a: rep stos %eax,%es:(%edi) 0x00007c1a in ?? () 1: x/i $pc => 0x7c1a: rep stos %eax,%es:(%edi) (gdb) info registers eax 0x0 0 ecx 0x8 8 edx 0x80 128 ebx 0x0 0 esp 0x7c00 0x7c00 ebp 0x800 0x800 esi 0x7e00 32256 edi 0x800 2048 eip 0x7c1a 0x7c1a eflags 0x246 [ PF ZF IF ] cs 0x0 0 ss 0x0 0 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0
途中で、rep付の命令に出会うと、ecxがZEROになるまで、足止めを喰らう事になる。そういう時は、ステップ実行を何回か勝手にgdbが行うように指示しよう。
途中でBIOSの中に潜り込んでしまい、本流が見えなくなる事がある。こういう時は、手元に アセンブルリストを用意して、止めたい所にBPを貼ってから継続すれば良い。
アセンブラーだと技巧的な事が出来て、読み込んだ512バイトを冒頭で0x600へ引っ越ししている。(次にboot1を読み込むため)そしてそこへ移動して実行してる。そんな事もあって、是非リストを手に入れておきたい。(CISCの糞石だと、命令長が可変だからね。行数数えて番地を割り出すなんて、無理な相談です。)
アセンブルリストを手に入れる常套手段は、objdump -S する事だけど、こやつは、codeとdataの区別がつかないという根源的な問題がある。
$ objdump -S boot0.out : 000007a7 <os_freebsd>: 7a7: 46 inc %esi 7a8: 72 65 jb 80f <__bss_start+0xf> 7aa: 65 gs
あたかも、そこに命令が有るように(適当に)表示されてしまった。まあ、甘いも辛いも分かってる人が使う分には手ごろでいいんだけどね。
じゃ、その解決方法は有るのか? アセンブルする時に、アセンブルリストを出すのが良い。-aがそれだ。何もオプションを与えないと結果が標準出力に出て来る。下記のようにすると、hogeってファイルに出力される。
$ as boot0.s -a=hoge
56 0000 FC start: cld # String ops inc 57 0001 31C0 xorw %ax,%ax # Zero GAS LISTING boot0.s page 2 : 394 01a7 46726565 os_freebsd: .ascii "Free"
上記は、hogeの出力。一番左の数値がソースの行番号。その右がアドレス。更に右側が命令コード若しくはデータ。その右側が、ソースだ。
このリスティングには、シンボルテーブルも最後についてくる。
DEFINED SYMBOLS *ABS*:000000b6 TICKS *ABS*:0000000f FLAGS boot0.s:20 *ABS*:00000475 NHRDRV boot0.s:21 *ABS*:00000600 ORIGIN : boot0.s:56 .text:00000000 start boot0.s:89 .text:00000022 main boot0.s:93 .text:0000002c main.1 : boot0.s:394 .text:000001a7 os_freebsd
詳細に確認したい時は便利だ。
(gdb) si 1: x/i $pc => 0x7c1f: jmp 0x46f70624 0x00007c1f in ?? () 1: x/i $pc => 0x7c1f: jmp 0x46f70624 (gdb) 1: x/i $pc => 0x622: testb $0x20,-0x45(%esi) 0x00000622 in ?? () 1: x/i $pc => 0x622: testb $0x20,-0x45(%esi) (gdb) b *0x68b Breakpoint 2 at 0x68b (gdb) c Continuing. 1: x/i $pc => 0x68b: xor %ah,%ah Breakpoint 2, 0x0000068b in ?? () 1: x/i $pc => 0x68b: xor %ah,%ah
上記、移動先へ遷移した所と、途中にあるBIOS呼び出しを飛ばして、少し先へBPを置いて、実行した例。0x600が移動先で、そこからの変位がアセンブラーリストに記されているので、足し算したアドレスにBPを置けばよい。
mbrの書き換え
いきなりだけど、説明を読むとMBRが読まれて、書き換えられているそうな。どんな風になってるか、調べてみる。
vboxに入れておいたFreeBSD5.1の冒頭セクターを取り出す
f51# dd if=/dev/ad0 of=org count=1 1+0 records in 1+0 records out 512 bytes transferred in 0.000308 secs (1662139 bytes/sec)
待ち時間を変更して、同じ事をする。
f51# boot0cfg -t 2 ad0 f51# dd if=/dev/ad0 of=two count=1 1+0 records in 1+0 records out 512 bytes transferred in 0.000188 secs (2725233 bytes/sec)
差異を比べてみる。
f51# cmp -x org two 000001bc b6 02
初期値のb6ってのは、10進数で182。一秒が18.2カウントに相当するので、 10秒も待たされる設定という事が判明。
書き換えるエリアが有るそうなので、ダンプしてみた。
f51# hd org : 000001a0 49 d8 4c 69 6e 75 f8 46 72 65 65 42 53 c4 90 90 |I.Linu.FreeBS...| 000001b0 66 bb 44 72 69 76 65 20 00 00 80 0f b6 00 80 01 |f.Drive ........|
How to make boot0
所で、boot0ってどうやって作ってるの? /sys/boot/i386/boot0にファイルとMakefileが置いてあったので、/tmpの下でコンパイルしてみた。
$ ls Makefile boot0.s $ make Warning: Object directory not changed from original /tmp as --defsym FLAGS=0xf --defsym TICKS=0xb6 boot0.s -o boot0.o ld -N -e start -Ttext 0x600 -o boot0.out boot0.o objcopy -S -O binary boot0.out boot0 $ ls Makefile boot0 boot0.o boot0.out boot0.s
FLAGSとTICKSは、コンパイル時に決定してるんだ。アセンブラにコマンドラインから変数を渡して、埋め込む方法が分かったよ。
# # These values are sometimes changed before writing back to the drive # Be especially careful that nxtdrv: must come after drive:, as it # is part of the same string. # drive: .ascii "Drive " nxtdrv: .byte 0x0 # Next drive number opt: .byte 0x0 # Option setdrv: .byte 0x80 # Drive to force flags: .byte FLAGS # Flags ticks: .word TICKS # Delay
install boot
所で、boot0は、インストール時にどんな風に使われているのかな? FreeBSD11.1では、bsdinstallがインストーラーだったんだけど、昔のインストーラーは、確か/stand/sysinstall だったはず。ソースを眺めてみたいな。入れてないから、ISOから追加しよう。
vboxだと、コンソール画面のウィンドウメニューから、デバイス->光学ドライブで、ISOを指定するんだな。
f51# df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 1775686 415072 1218560 25% / devfs 1 1 0 100% /dev
あれれ、cdromが見えないぞ。こういう時は、/etc/fstabにヒントがきっとあると思うので見る。
f51# mount /dev/acd0 f51# df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/ad0s1a 1775686 415072 1218560 25% / devfs 1 1 0 100% /dev /dev/acd0 630048 630048 0 100% /cdrom
f51# ls /cdrom 5.1-RELEASE INSTALL.TXT catpages crypto packages EARLY.HTM README.HTM cdrom.inf dict ports EARLY.TXT README.TXT compat1x doc proflibs ERRATA.HTM RELNOTES.HTM compat20 docbook.css src ERRATA.TXT RELNOTES.TXT compat21 floppies tools HARDWARE.HTM base compat22 games HARDWARE.TXT boot compat3x info INSTALL.HTM boot.catalog compat4x manpages
srcの下あたりを見ると、1.44Mにsplitされたファイルが多数入っていたぞ。OSをフロッピーで 回覧@日経MIXとかが懐かしいな。
sysinstallを起動して、configureからdistoributionを選んで、必要そうなソースを追加したよ。もう10年ぐらいは、このオペレーションをやっていないはずなんだけど、意外に覚えているものだな。
pkgも少ないけど同梱されてた。editorsの項を見ると、emacs 21.3 なんてのが入っていた。懐かしいバージョンだな。
release
CDのイメージをどうやって作っているんだろう? そういう時は出荷方法を見ればいいのかな。 てな事で、 /usr/src/release/scripts/doS.shを覗いてみた。
if [ -f "${RD}/trees/base/boot/boot" ]; then BOOT="-B -b ${RD}/trees/base/boot/boot" elif [ -f "${RD}/trees/base/boot/boot1" ]; then BOOT="-B -b ${RD}/trees/base/boot/boot1" if [ -f "${RD}/trees/base/boot/boot2" ]; then BOOT="${BOOT} -s ${RD}/trees/base/boot/boot2" fi else BOOT="-r" fi : dd of=${FSIMG} if=/dev/zero count=${FSSIZE} bs=1k 2>/dev/null vnconfig -s labels -c /dev/r${VNDEVICE} ${FSIMG} disklabel -w ${BOOT} ${VNDEVICE} ${FSLABEL} newfs -i ${FSINODE} -o space -m 0 /dev/r${VNDEVICE}c
zeroで埋めたファイルを作ってから、boot関係者を、disklabelコマンドで登録してるんだな。 それからファイルシステムを作ってる。あれ、fdisk相当はやっておかなくてもいいのかな?
Completely wipe any prior information on the disk, creating a new bootable disk with a DOS partition table containing one slice, covering the whole disk. Initialize the label on this slice, then edit it. The dd(1) commands are optional, but may be necessary for some BIOSes to properly recognize the disk: dd if=/dev/zero of=/dev/da0 bs=512 count=32 gpart create -s MBR da0 gpart add -t freebsd da0 gpart set -a active -i 1 da0 gpart bootcode -b /boot/mbr da0 dd if=/dev/zero of=/dev/da0s1 bs=512 count=32 bsdlabel -w -B da0s1 bsdlabel -e da0s1
man bsdlabelに上記のような例が出てた。fdiskなんて古いからgpartを使えとな。
# $FreeBSD: releng/11.1/release/picobsd/qemu/PICOBSD 274331 2014-11-09 21:33:01Z melifaro $ # A configuration file to run tests on qemu. # We disable SMP because it does not work well with qemu, and set HZ=1000 # to avoid it being overridden.
面白い物を発見した。FreeBSDもqemuで楽しんで下さいとな。HZは普通のやつだと100なんだけど、1000にする。これはオイラーが前回やった時に、GUIだと入力応答が悪いと嘆いていたのの対策であろうか。
確かにプロセスの切り替え頻度を頻繁(当社比10倍)にすれば、応答は良くなるな。但し、ホストのCPU負荷は上がると思われる。カーネルを直接にパッチして実験してみるかな。
(gdb) p hz $4 = 100 (gdb) p hz=1000 $5 = 1000
返って、応答が悪くなったような気がするよ。どういう意図で1000にしてるんだろう? hz=50ぐらいにした方が、つっかかりが無いぞ。
そして、この値はDATAセクションに置いてあるかと思ったら、BSSエリアに有った。ブートの途中で、初期化されてるんだな。どこでやってるのだろうか?
そんな事より、kernelをnmして、hzの場所を特定した。今の値は50にしてるんで、そうなってるか確認してみる。
(gdb) x/w 0xc030defc 0xc030defc <hz>: 50
gdbが有れば、kernelもただの大きなアプリじゃんと思うぞ。
kernel ダイエット
下記、kernelを作る時のconfigファイルから、コメントと空行を削除した結果。
deb9:conf$ egrep -v '^#' SAKAE | sed '/^$/d' machine i386 cpu I486_CPU cpu I586_CPU cpu I686_CPU ident SAKAE hints "GENERIC.hints" #Default places to look for devices. makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols makeoptions NO_MODULES=yes options SCHED_4BSD #4BSD scheduler options INET #InterNETworking options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support options UFS_ACL #Support for access control lists options UFS_DIRHASH #Improve performance on big directories options MD_ROOT #MD is a potential root device options CD9660 #ISO 9660 Filesystem options PROCFS #Process filesystem (requires PSEUDOFS) options PSEUDOFS #Pseudo-filesystem framework options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!] options COMPAT_FREEBSD4 #Compatible with FreeBSD4 options SCSI_DELAY=15000 #Delay (in ms) before probing SCSI options SYSVSHM #SYSV-style shared memory options SYSVMSG #SYSV-style message queues options SYSVSEM #SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions options KBD_INSTALL_CDEV # install a CDEV entry in /dev options AHC_REG_PRETTY_PRINT # Print register bitfields in debug # output. Adds ~128k to driver. options AHD_REG_PRETTY_PRINT # Print register bitfields in debug # output. Adds ~215k to driver. options DDB #Enable the kernel debugger options DDB_NOKLDSYM options INVARIANT_SUPPORT #Extra sanity checks of internal structu res, required by INVARIANTS device isa device eisa device pci device fdc device ata device atadisk # ATA disk drives device atapicd # ATAPI CDROM drives device atapifd # ATAPI floppy drives device atapist # ATAPI tape drives options ATA_STATIC_ID #Static device numbering device atkbdc # AT keyboard controller device atkbd # AT keyboard device psm # PS/2 mouse device vga # VGA video card driver device sc device npx device pmtimer device sio # 8250, 16[45]50 based serial ports device em # Intel PRO/1000 adapter Gigabit Ethernet Card device miibus # MII bus support device random # Entropy device device loop # Network loopback device ether # Ethernet support device sl # Kernel SLIP device ppp # Kernel PPP device tun # Packet tunnel. device pty # Pseudo-ttys (telnet etc) device md # Memory "disks" device gif # IPv6 and IPv4 tunneling device faith # IPv6-to-IPv4 relaying (translation) device bpf # Berkeley packet filter
最後の方にある仮想デバイスslだとかpppだとかgifなんてのを削れるね。世の中ではそろそろ、IPv6 Readyな気配もあるようなんでね。
etc
Google 翻訳の利用:PDFやWordのファイルを翻訳する方法
booklet これ、調布にある大学のパソコン部だかが出してる部報のアーカイブ。暇に任せて読むのには丁度よいな。