boot

add disk

VMWAREでDISK増設とかやったけど、qemuの場合はどうやる? 軽くぐぐったら素晴しい資料に出会った。全機能を使ってみるなんでとっても無理です。

QEMU by archlinux

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

The amd64 Boot Process

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

急に寒くなって俄に血圧が上昇中。季節を微分した結果が血圧に反映されてるっぽい。ならば季節による分析だな。確か過去にやってるね。

R言語 (2)

Rと時系列(1)

それをそのまま撫ぞってもいいんだけど、今回は手慰めで前段階の部分を書いてみるか。 昔のコマンドのオンパレードで、月毎の朝の最高血圧の平均を出してみた。 元データはこんなの。

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なんてのが、出来上がるな。知らなかったぞ。


This year's Index

Home