boot
add disk
VMWAREでDISK増設とかやったけど、qemuの場合はどうやる? 軽くぐぐったら素晴しい資料に出会った。全機能を使ってみるなんでとっても無理です。
sakae@deb:~/sim/QEMU$ qemu-img create -f qcow2 ext.img 1G Formatting 'ext.img', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16 sakae@deb:~/sim/QEMU$ ls -l ext.img -rw-r--r-- 1 sakae sakae 196624 Oct 7 07:46 ext.img
取り敢えず追加用のDISKを作成。起動スクリプトに -hdb ext.img を追加して認識させよう。
qm# dmesg | grep wd wd0 at pciide0 channel 0 drive 0: <QEMU HARDDISK> wd0: 16-sector PIO, LBA48, 3072MB, 6291456 sectors wd1 at pciide0 channel 0 drive 1: <QEMU HARDDISK> wd1: 16-sector PIO, LBA48, 1024MB, 2097152 sectors wd0(pciide0:0:0): using PIO mode 4, DMA mode 2 wd1(pciide0:0:1): using PIO mode 4, DMA mode 2 root on wd0a (f1bc5dab4c1884ce.a) swap on wd0b dump on wd0b
どうやら認識した。ここからはゲストOS内での作業。
qm# disklabel -E wd1 Label editor (enter '?' for help at any prompt) wd1> p OpenBSD area: 0-2097152; size: 2097152; free: 2097152 # size offset fstype [fsize bsize cpg] c: 2097152 0 unused wd1> wd1> wd1> a a offset: [0] size: [2097152] FS type: [4.2BSD] wd1*> w wd1> q No label changes. qm# newfs wd1a /dev/rwd1a: 1024.0MB in 2097152 sectors of 512 bytes 6 cylinder groups of 202.50MB, 12960 blocks, 25920 inodes each super-block backups (for fsck -b #) at: 160, 414880, 829600, 1244320, 1659040, 2073760, qm# mount /dev/wd1a /mnt qm# df -k Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/wd0a 2674670 794640 1746298 31% / /dev/wd1a 1009422 2 958950 0% /mnt
fdiskでMSDOSにも理解出来るパーテションを作ってしまうと、なにも処置をしなければ起動DISKになっちゃう。この場合はqemuはどう反応する? 実験してみてもいいんだけど無駄なんで、いきなりdisklabelしたよ。後はfstabに登録だね。
で、この追加DISKに何を入れる? ざーと考えてsrcでも入れておくか。ならばcurlとか必要? あれは機能豊富で、時々緊急対策を要求されるからなあ。。で、それに変わるものはないの?
散歩の途中で閃いた。OSをインストールする時、アップグレードも選べたはず。と言う事はデフォルトでcurl相当が用意されてるはず。調べてみたら、なんとftpが使われていた。
AUTO-FETCHING FILES In addition to standard commands, this version of ftp supports an auto- fetch feature. To enable auto-fetch, simply pass the list of hostnames/files on the command line. The following formats are valid syntax for an auto-fetch element: host:/file[/] "Classic" ftp format. ftp://[user:password@]host[:port]/file[/] An FTP URL, retrieved using the FTP protocol if ftp_proxy isn't defined. Otherwise, transfer using HTTP via the proxy defined in ftp_proxy. If a user and password are given and ftp_proxy isn't defined, log in as user with a password of password. http://[user:password@]host[:port]/file :
qm$ ftp https://ftp.riken.jp/OpenBSD/7.1/src.tar.gz Trying 134.160.38.1... Requesting https://ftp.riken.jp/OpenBSD/7.1/src.tar.gz 100% |**************************************************| 191 MB 03:55 200437451 bytes received in 235.23 seconds (832.11 KB/s)
適当にDISKを用意しちまったものだから DISK FULL攻撃を受けました。ご利用は計画的に!!
tar: Unable to create usr.sbin/zic/zic.8: No such file or directory tar: Unable to mkdir usr.sbin/zic: No space left on device tar: Unable to create usr.sbin/zic/zic.c: No such file or directory qm# df Filesystem 512-blocks Used Avail Capacity Mounted on /dev/wd0a 5349340 1981024 3100852 39% / /dev/wd1a 2018844 2018844 -100940 105% /mnt
で、そのまま再起動しちゃうと、途中でshellに落ちてfsckを要求される。 挙句の果て、問題有りのDISKと認識されmountも出来無かった。こうなったら、DISKの初期化しなないな。
問題は発生時点で対処すべきって、人生訓を再確認させられたぞ。そう、先延しするな、です。
on debian
OpenBSDから仮想DISKと/sys一式をコピーして、debinan(32bit)でも試してみた。
(gdb) bt #0 setroot (bootdv=0xd140c000, part=0, exitflags=16384) at /usr/src/sys/kern/subr_disk.c:1406 #1 0xd02b10de in diskconf () at /usr/src/sys/arch/i386/i386/autoconf.c:255 #2 0xd02607f3 in main (framep=0x0) at /usr/src/sys/kern/init_main.c:461
(gdb) n 1578 rootdev = MAKEDISKDEV(majdev, rootdv->dv_unit, part); (gdb) n 1579 nswapdev = MAKEDISKDEV(majdev, rootdv->dv_unit, 1); (gdb) 1586 dumpdev = nswapdev; (gdb) p rootdev $2 = 0 (gdb) p nswapdev $3 = 1
この通り、普通に動いた。
cscopeのDBも一緒について来たんだけど、こちらはfatalエラーになってしまって動かなかった。再度DBを作ったよ。機種依存牲がありますだな。
boot
FAQを見ていたら、面白い解説を発見。カーネルがどうやってメモリーに載って來るか。そしてbootの役割とかね。
Using drive 0, partition 3. <- MBR Loading...... <- PBR probing: pc0 com0 com1 mem[638K 1918M a20=on] <- /boot disk: hd0+ hd1+ >> OpenBSD/amd64 BOOT 3.33 boot> booting hd0a:/bsd 4464500+838332 [58+204240+181750]=0x56cfd0 entry point at 0x100120
boot option
bootコマンドからddbを呼び出せるとな。別のコマンドを使うと、デバイスの設定とかも出来るそうだ。詳しくは、boot(8)
Booting from Hard Disk... Using drive 0, partition 3. Loading...... probing: pc0 com0 apm pci mem[639K 62M a20=on] disk: fd0 hd0+ >> OpenBSD/i386 BOOT 3.44 switching console to com>> OpenBSD/i386 BOOT 3.44 boot> 0 -d booting hd0a:/bsd: 13912599+2241540+241672+0+1130496 [97+802512+713363]=0x122b3c entry point at 0x201000 [ using 1516508 bytes of bsd ELF symbol table ] Stopped at db_enter+0x4: popl %ebp ddb> p dumpdev d11a3054 ddb> c Copyright (c) 1982, 1986, 1989, 1991, 1993 :
こんなコマンドって面白そう。
diskinfo Prints a list of hard disks installed on your system including: BIOS device number, and the BIOS geometry. gop [mode] On efifb(4) systems, sets the video resolution in pixels to mode. If mode is not given, a list of available modes is shown.
my boot
bootコマンドの改造なんて、おぼつかないので、qemuのbootを少し充実させてみた。
#!/bin/sh SF= EF= while getopts "SE" opt; do case $opt in S) SF='-S';; E) EF='-hdb ext.img';; *) echo 'Usage: boot [-S] [-E]' echo ' -S cpu Stop at startup' echo ' -E Enable 2nd disk' exit 1;; esac done qemu-system-i386 -m 64 -nographic -no-fd-bootchk -s $SF \ -net nic -net user,hostfwd=tcp::2022-:22 \ -hda virtual.img $EF
ここで使っている getopts は、shellの組み込みコマンドだ。
Make
カーネルをコンパイルした時、オプチマイザーをかけない指定をしたはずなんだけど、どうも最適化されてる節がある。でMakefileを見なおしてみた。下記はその超簡単版数。DEBUG変数は、configに記述したものが反映されてる。
DEBUG=-g COPTIMIZE?= -O2 CFLAGS= ${DEBUG} ${COPTIMIZE} ${COPTS} NORMAL_C= ${CC} ${CFLAGS} all: ${NORMAL_C} sample.c
簡単な実行。COPTSを環境変数として渡すと、二重に出て来る。これでいいのか?
vbox$ make cc -g -O2 sample.c vbox$ COPTS="-O0" make cc -g -O2 -O0 sample.c
あらかじめ定義されてるOPTIMIZEに定義しておいた方がいいのかな。下記は初回のコンパイル結果。
-rwxrwx--- 1 root wobj 63552224 Oct 3 13:40 bsd.gdb* -r--r--r-- 1 root wobj 12896745 Oct 3 13:40 bsd
-g -O0 に変更してコンパイルしたら、一箇所エラーだったのでフレームサイズを2047から3047に変更した。
CWARNFLAGS= -Werror -Wall -Wimplicit-function-declaration \ -Wno-pointer-sign \ -Wframe-larger-than=3047
下記は、コンパイルの最後の部分。
LD="ld" LDFLAGS="-melf_i386" sh makegap.sh 0xcccccccc gapdummy.o cc -g -O0 -Werror -Wall -Wimplicit-function-declaration : -MP -c /usr/src/sys/conf/swapgeneric.c ld -T ld.script -X --warn-common -nopie -melf_i386 -o bsd ${SYSTEM_HEAD} vers.o ${OBJS} text data bss dec hex 16140495 246900 1130496 17517891 10b4d43 mv bsd bsd.gdb ctfstrip -S -o bsd bsd.gdb ob# ls -l bsd.gdb bsd -rwxrwx--- 1 root wobj 17916863 Oct 8 15:30 bsd -rwxrwx--- 1 root wobj 63997100 Oct 8 15:30 bsd.gdb
本稼動するbsdはctfstripを使ってDEBUG情報を削除してる。
get var address
kernelの変数アドレスをnmコマンドで抽出すると、どうも並びが不規則だ。名前でソートしてある訳でもなく、アドレス順でもない。名前なら簡単にソート出来るけど、アドレス順にソートしようとすると16進数に阻まれて、そのままでは出来無い。 そんな訳で、アドレス順にソートするスクリプトを作ってみた。
gawkだと、16進数を容易に10進数に変換出来るけどBSD系は、そんなのない。 一度、0xをつけたファイルを掃き出し、それを使って10進数を冒頭につけてからソートなんて事をやっている。
#!/bin/sh temp=/tmp/zz$$ nm bsd | grep ' D' | awk '{ printf "%s %s %s %s\n", "0x" $1, $1, $2, $3 }' >$temp while read line do printf "%d %s %s %s\n" $line done < $temp | sort -n | cut -f2- -d' ' rm -f $temp
00d3b000 D __kernel_kudata_phys d0d04330 D pcibios_cd d0d04344 D ep_isapnp_ca d0d04358 D ftlock d0d04360 D sm_isa_ca : d0d3ae1c D vmt_cd d0d3ae30 D rootdev d0d3ae34 D dumpdev d0d3ae38 D swdevt
変数の〆るアドレス幅が色々あって、これはきっと構造体だろうなんて予測が出来て、面白いぞ。
patch ?
kernelファイルのデータエリアを確認もしくは書き換えてみたい。目標はdumpdevの所。
ob$ objdump -h bsd bsd: file format elf32-i386 Sections: Idx Name Size VMA LMA File off Algn : 4 .data 00036e48 d0d04000 00d04000 00b04000 2**12 CONTENTS, ALLOC, LOAD, DATA
このコマンドでデータエリアのファイルのオフセットが分る。それに対してのアドレスも分る。
ob$ gdb -q (gdb) p/x (0xd0d3ae34 - 0xd0d04000) ;; var_adr - VMA $1 = 0x36e34 (gdb) p/x ($1 + 0x00b04000) ;; diff + File_off $2 = 0xb3ae34
ob$ hexedit bsd Ctl+g New position ? 0xb3ae34 : vv 00B3AE30 FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 ................ -%% bsd --0xB3AE34/0xC4C9E9--91%----------------------------------------
hexeditを使って、ファイルの先頭からの変位へJUMP。カーソルは vv の位置に移動した。後は煮るなり焼くなりご自由に。
まあ、データエリアは、OSの稼動に伴って書き変わる運命だから、余り役にたつとは思えないけど。
ちなみにデータエリアの先頭(VMA)は、こんな風になってた。
ob$ nm bsd | grep d0d04000 d0d04000 A __data_start d0d04000 D _erodata d0d04000 D erodata d0d04000 D __kernel_data_virt
ts.plot
急に寒くなって俄に血圧が上昇中。季節を微分した結果が血圧に反映されてるっぽい。ならば季節による分析だな。確か過去にやってるね。
それをそのまま撫ぞってもいいんだけど、今回は手慰めで前段階の部分を書いてみるか。 昔のコマンドのオンパレードで、月毎の朝の最高血圧の平均を出してみた。 元データはこんなの。
sakae@deb:/tmp/t$ head -4 current.csv 12010104,118,73,57 12010121,109,70,71 12010204,128,82,60 12010221,105,62,67
我乍ら、よく記録したものだ。
#!/bin/sh cat current.csv | egrep '^(1|2).....0' | cut -b1-4,9-12 | awk -F',' '{s[$1] += $2; c[$1] +=1} \ END {for (i in s){print i, ",", s[i] / c[i]} }' | sed -e 's/^/20/' | sort -n >bld.csv
emacs からの実行、C-c C-x ってのをいつも忘れるんだよな。それだけ稀って事だ。
年月日時で始まるフィールドから1X年か2X年の朝だけのデータを抽出。それを年月、最高血圧だけにする。awkの連想配列を作る。合計と個数から月の平均を求める。冒頭に20を付けて、202210,135.8みたいに変形。最後は数値で並び換えて出力。
sakae@deb:/tmp/t$ head -4 bld.csv 201201 , 125.065 201202 , 123.276 201203 , 120.967 201204 , 118.167
次はR言語用のスクリプトだ。上で作ったCSVを読込み。そいつのカラムに名前を付ける。そしてタイムシリーズ用に変換。それをグラフ表示。最後は、トレンドと周期と誤差に分解したものをPDFファイルに落とす。1年を周期とするFFTみたいなものだな。
#!/usr/bin/Rscript bld <- read.csv("bld.csv", header = F) colnames(bld) <- c("yyyymm","hi") hi.ts <- ts(bld$hi, start=c(2012,1), frequency=12) ts.plot(hi.ts) pdf("OUTPUT.pdf") plot(decompose(hi.ts)) dev.off()
スクリプトとして走らせると勝手にRplots.pdfなんてのが、出来上がるな。知らなかったぞ。