OpenBSD観光

『日本人は知らない中国セレブ消費』なんて言う本を読んだ。帯に、なぜ角部屋を彼らは嫌う? と言うキャッチが踊っていたから、ついつい手にした次第。著者は、上海生まれの方。日本に留学して、就職して、日本を体験した。その後、上海に戻って、日本の体験を生かして、セレブをターゲットにした雑誌を発行してるとか。

帯の答え、オイラーの予想は、角部屋では日光で家具が傷むだろうってもんだ。そんなの西洋の思想って軽くいなされたよ。風水ですよ。

角部屋と言うと、マンションでもホテルでも、大体が廊下の突き当りにある。邪気も廊下を伝わってきて角部屋に入り込む。中国人は、そんな邪気が漂う部屋には入りたくないぞと思うんだとか。

ホテルとかで、そんな部屋を割り当てられたら、まずは普通の部屋に部屋替えを依頼するらしい。だめなら、入室の時、大きな声を出して邪気を追い払うそうな。

著者は日本で旅行業界に居たんで、その経験を生かして旅行雑誌を発行してるんだけど、中国人の 思想を縦横に語っている。

日本は中国に無い文化と正直な国民性が評価され、何度も訪れたい国になってる。上海からだと九州へ来る方が北京に行くよりずっと近い。

豪華な刺身が大好き。生の魚を切っただけの料理なんで、誤魔化し様が無いから。そして、インスタ映えが、面子大好きな彼らにはぴったりだそうだ。

その他、色々と中国人をお得意様にする方法が紹介されてた。

詳しくしようは、失敗

前回qemuにOpenBSDを入れて、gdbから操れるようにした。こういうのは、みなさんやってる遊びなんですなあ。

Memo: How to build OpenBSD from source code and add system call on QEMU

こちらの方も、システムコールを追加する遊びまでやっておられて、良い道標になりますよ。

それはそうと、gdbから操れるって言っても、問題が無いとは言えない。関数の引数や、内部で 使われている変数をprintしようとすると、それはoptimizeされてるんで表示出来ないのよと言われるんだ。気分が落ち込みますなあ。

コンパイルする時に、最適化無しを指定すると、エラーになってしまい、カーネルが完成しなかったんだ。先を急ぐんで、涙をのんだわけ。でも、惜しいな。

man clang して、最適化を見ると、-O0 の他に、-Og てのも載ってたけど、これは将来のお楽しみらしい。

真面目にエラーと向き合う事にしたよ。で、最初に表われたエラーは、pf_iostat だったかの 関数に関するエラー。フレームサイズが一定以上になってると、それっておかしいんじゃねぇと 目を付けられるんだ。最適化しないんで、余計なものがフレームに残るんでしょうな。

何処かに、リミット値が書かれているはずだと思って調べたら、下記のMakefileに指定してあった。AMDのagp関数も通過出来るように、非常に大きな値にしてる。

cat i386/conf/Makefile.i386
                   :
                -Wframe-larger-than=6047  ## org is 2047

COPTS="-O0" make  又は
COPTS="-Og" make

そして、上記のオプションでコンパイルしたが、エラーですよ。

ld -T ld.script -X --warn-common -nopie -o bsd ${SYSTEM_HEAD} vers.o ${OBJS}
aic79xx.o: In function `ahd_handle_seqint':
/usr/src/sys/dev/ic/aic79xx.c:1131: undefined reference to `ahd_assert_atn'
/usr/src/sys/dev/ic/aic79xx.c:1177: undefined reference to `ahd_assert_atn'
  :
pipex.o: In function `pipex_mppe_output':
/usr/src/sys/net/pipex.c:2534: undefined reference to `pipex_mppe_setkey'
/usr/src/sys/net/pipex.c:2559: undefined reference to `pipex_mppe_crypt'
  :
wskbdutil.o: In function `wskbd_compose_value':
/usr/src/sys/dev/wscons/wskbdutil.c:209: undefined reference to `compose_tab_cmp'
i915_gem_gtt.o: In function `i915_gem_setup_global_gtt':
/usr/src/sys/dev/pci/drm/i915/i915_gem_gtt.c:2712: undefined reference to `intel_vgt_balloon'
  :
ahd_pci.o: In function `ahd_find_pci_device':
/usr/src/sys/dev/pci/ahd_pci.c:305: undefined reference to `ahd_compose_id'
*** Error 1 in /usr/src/sys/arch/i386/compile/DEBUG (Makefile:992 'bsd': @echo ld -T ld.script -X --warn-common -nopie -o bsd '${SYSTEM_HEAD...)

エラーを手掛かりに、ググル先生に聞いてみたけど、まだ誰も報告を上げていない。はて、どうしたものか? メーリングリストに加わって聞いてみたいけど、流量が多そうで躊躇してる。

ob6$ cc -v
OpenBSD clang version 5.0.1 (tags/RELEASE_501/final) (based on LLVM 5.0.1)
Target: amd64-unknown-openbsd6.3
Thread model: posix
InstalledDir: /usr/bin
ob6$ gcc -v
Reading specs from /usr/lib/gcc-lib/amd64-unknown-openbsd6.3/4.2.1/specs
Target: amd64-unknown-openbsd6.3
Configured with: OpenBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070719

もしものためにgccも残してあるけど、これでコンパイル出来るのかなあ。上であげたMaMakefile.i386が元締めっぽいんで、これを変更して試してみるかな。

for kernel debug

上でgccに思いが至ったのは、オイラーの知らないオプションが出て来たから。clangの説明にも 載ってなかったんだ。こういう時は先輩のgccに尋ねてみるのがセオリー。脊髄反射で、man gccとしてたのさ。そしたら、ちゃんと説明が出て来た。だったら、 本体も居るんじゃねぇ? 何もかもググル先生に聞くのは止しましょう。

んでもって、お試しに

ob6# config SS
ob6# cd ../compile/SS
ob6# vi obj/Makefile
ob6# CC=gcc make

Makefileで変更したのは、下記部分

COPTS?=         -O0

configすると、ヘッダーファイル類とMakefileがobjの下に作られる。このMakefileは、config時に、Makefile.i386がコピーされるっぽい。だから、このMakefileはいじり倒してもOK。それから、このMakefileを見てて気が付いたんだけど、amd64な環境でも、ちゃんとi386用にコンパイルしてくれるのね。そんな事は知らんかったわい。

で、コンパイルすると、Intel i915の所で失敗する。どうせ、qemuで実行するんだから、X関係者なんていらないでしょ。それからついでに、ATI Radeon DRM driver の部分もコメントアウトしておいたよ。(これ不完全、後述のkernel for debugを試せ)

kernel startup 観光旅行

気分を変えるって事で、旅にでる事にした。

カーネルが起動して、ログインメッセージが出て来るまでを、ドキュメント風に追ってみる。定番の観光コースですな。

コンソールには、com0を設定。

ss63$ cat /etc/boot.conf
set tty com0

ああ、これは、qemu配下のターゲットOpenBSD側ね。

そして、

qemu-system-i386 -m 256  -S -s \
  -serial pty \
  -net nic -net user,hostfwd=tcp::2022-:22 disk &

こんな設定で、qemuをスタート。すかさず、シリアルラインにcuで接続しておく。

QEMUの画面は、guest has not initialized the display (yet). で待ち受けです。

Reading symbols from bsd.gdb...done.
0x0000fff0 in ?? ()
(gdb) b main
Breakpoint 1 at 0xd08c2720: file /usr/src/sys/kern/init_main.c, line 192.
(gdb) c
Continuing.

Breakpoint 1, main (framep=<error reading variable: Cannot access memory at add\
ress 0x8>) at /usr/src/sys/kern/init_main.c:192
192     {
(gdb)

進み具合の優先権はgdbにあるので、mainにBPを置いてcontinueする。(FreeBSDはmainなんてのは無かったような気がしたぞ。OpenBSDは優しい作りだな。)

Booting from Hard Disk...
Using derive 0, partition 3.
Loading.......
probing: pc0 com apm pci mem[639K 254M a20=on]
disk: fd0 hd0+
>> OpenBSD/i386 BOOT 3.31
switching console to com0

この時、QEMUのコンソールには、こんな案内が出て来る。

cu -l /dev/ttyp4
Connected to /dev/ttyp4 (speed 9600)

    >> OpenBSD/i386 BOOT 3.31
boot>
booting hd0a:/bsd: 8119572+2216964+164616+0+1089536 [662718+82+492608+504331]=0xca5524
entry point at 0x2000d4

[ using 1660196 bytes of bsd ELF symbol table ]

シリアルライン側の表示。mainで止まった時は、カーネルがローディングされた状態。

(gdb)
230             cpu_startup();
(gdb)
232             random_start();         /* Start the flow */

gdbのnextを実行した。

Copyright (c) 1982, 1986, 1989, 1991, 1993
        The Regents of the University of California.  All rights reserved.
Copyright (c) 1995-2018 OpenBSD. All rights reserved.  https://www.OpenBSD.org

OpenBSD 6.3 (DEBUG) #5: Tue Jun  5 14:20:13 JST 2018
    sakae@ob.happy.net:/usr/src/sys/arch/i386/compile/DEBUG
cpu0: QEMU Virtual CPU version 2.5+ ("GenuineIntel" 686-class) 2.41 GHz
cpu0: FPU,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,PGE,CMOV,MMX,FXSR,SSE,SSE2,SSE3,HV
real mem  = 267796480 (255MB)
avail mem = 248979456 (237MB)

見慣れたバナーが出て来たな。

366             config_rootfound("mpath", NULL);
(gdb)
370             cpu_configure();

少し先まで進める。

mpath0 at root
scsibus0 at mpath0: 256 targets

マザーボードのバスの検出でしょうか?

369        /* Configure the devices */
370        cpu_configure();

ちょっとgdbの魚拓を取り忘れてしまったけど、370行目が実行されると、ドドーンと デバイスの認識が行われる。

  :
pckbc0 at isa0 port 0x60/5 irq 1 irq 12
pckbd0 at pckbc0 (kbd slot)
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pms0 at pckbc0 (aux slot)
wsmouse0 at pms0 mux 0
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
lpt0 at isa0 port 0x378/4 irq 7
npx0 at isa0 port 0xf0/16: reported by CPUID; using exception 16

そして、この行が(dmsgにも出てるだろうけど)表示された所で、ステップをしても 粛々と内部のソフト的な準備が進むようである。

570             start_periodic_resettodr();
(gdb)
576                     tsleep(&proc0, PVM, "scheduler", 0);
(gdb)

そして、遂に変化が表れて。ここからはinitさんが、/etc/rcを解釈実行してくんだな。

Automatic boot in progress: starting file system checks.
/dev/wd0a (0496db44f78111d2.a): file system is clean; not checking
setting tty flags
pf enabled
starting network
em0: bound to 10.0.2.15 from 10.0.2.2 (52:55:0a:00:02:02)
fd0 at fdc0 drive 1: density unknown
starting early daemons: syslogd.
starting RPC daemons:.
savecore: /dev/wd0b: Device not configured
checking quotas: done.
clearing /tmp
kern.securelevel: 0 -> 1
creating runtime link editor directory cache.
preserving editor files.
starting network daemons: sshd.
starting local daemons:.
Sat Jun  9 15:35:39 JST 2018

ここで、initさんの初期仕事はおしまい。後は、監視役になるのか。

575             while (1)
(gdb) n
576                     tsleep(&proc0, PVM, "scheduler", 0);

で、何度かこのルーチンを回ると

OpenBSD/i386 (ss63.my.domain) (tty00)

login:

gettyだかが起動してくるんだな。やっと、見慣れた所に到達した。 同様なログインメッセージは、QEMUのコンソールにも出て来たぞ。

ss63$ dmesg | tail
lpt0 at isa0 port 0x378/4 irq 7
npx0 at isa0 port 0xf0/16: reported by CPUID; using exception 16
nvram: invalid checksum
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
scsibus3 at softraid0: 256 targets
root on wd0a (0496db44f78111d2.a) swap on wd0b dump on wd0b
clock: unknown CMOS layout
fd0 at fdc0 drive 1: density unknown

改めて確認すると、ここまでがカーネルさんのお仕事なんだな。

kernel for debug

amd64のマシンで、最適化しないkernelを作ってみた。ログインすると

login: sakae
Password:
Last login: Sat Jun  9 07:00:05 on tty00
OpenBSD 6.3 (SS) #0: Sat Jun  9 14:20:47 JST 2018

NO LOGINS: System going down at 9:00

なんだか、意味不なメッセージが出て来たぞ。なんじゃらほい? そして致命的な出来事が。。。隣の端末からsshでログインしようとしたら、

ss63$ uvm_fault(0xd0c7ce80, 0x0, 0, 1) -> e
kernel: page fault trap, code=0
Stopped at      pf_set_protostate+0x3d: movzbl  0x27(%eax),%eax
ddb>
ddb> trace
pf_set_protostate(d170bb60,0,2,d081158f,d168c480) at pf_set_protostate+0x3d
pf_create_state(f36eeec0,d194979c,0,0,f36eee38) at pf_create_state+0x497
pf_test_rule(f36eeec0,f36eefa8,f36eefa4,f36eefac,f36eefa0) at pf_test_rule+0xbca
pf_test(2,1,d176b030,f36ef054,f36ef058) at pf_test+0x94a
ip_input_if(f36ef054,f36ef064,4,0,d176b030) at ip_input_if+0x32c
ipv4_input(d176b030,d178e800,6,d08a18e0,800) at ipv4_input+0x4c
ether_input(d176b030,d178e800,0,d0939192,0) at ether_input+0x2bc
if_input_process(d176b030,f36ef118,f36ef12c,d090f446,d171d054) at if_input_process+0x81
ifiq_process(d176b27c,f36ef158,d0731665,0,0) at ifiq_process+0x79
taskq_thread(d171d040) at taskq_thread+0x5c

この通り、ddb君がお出まししました。これじゃ、危なくておちおち観光旅行出来ないな。 無理して、amd64なコンパイラーで、i386用のカーネルを作るという、細い道を通ったから、地雷を踏んじゃったかしらん。

幸いバックアップとして、virtualboxにi386な環境を作ってあるんで(ポータブルOpenBSDを作る積りでインストールしたんだけど)、そこで製造したカーネルを持ってこよう。

どうせなら、多用されているマクロを展開・確認出来るようにしておくか。そんな訳で、Makefileに次のような変更を加えておいた。

DEBUG=-g3
COPTS?=         -O0 -gdwarf-2

これでコンパイルすると、最後の最後で、リンカーにg3なんてオプションは無いぞと文句を 言われる。Makefileのg3をgにしてから、コンパイル再開。無事にカーネルが出来た。bsd.gdbが通常サイズの40M前後から、260Mに膨れ上がってしまったぞ。

走らせてみると、やはりsshとかscpは、中から外、外から中とも、ddbに落ちてしまう挙動。 でも、マクロの展開が出来るようになったんで、これで佳しとするか。こちらの方が絶対的に便利ですから。

(gdb) info macro ENXIO
Defined at /usr/src/sys/sys/errno.h:47
  included at /usr/src/sys/sys/param.h:75
  included at /usr/src/sys/dev/audio.c:17
#define ENXIO 6

単純な確認

(gdb) macro expand FILE_SET_MATURE(fp,p)
expands to: do { (fp)->f_iflags &= ~0x02; (--(fp)->f_count == 0 ? fdrop(fp, p) \
: 0); } while (0)

Lispで言うなら、マクロエキスパンドだな。

このカーネルだと、観光には便利なんだけど、何かをネット越しに転送する事が出来ない。 従来のカーネルも入れておいて、必要に応じて切り替えて使えばいいな。

例えば、ssh出来るカーネル(clangで普通にコンパイルした奴)を、/bsdSSH っていう名前で登録しとく。起動してbootプロンプトが出てきたら素早くスペースを叩く。後は落ち着いて

boot>   boot hd0a:/bsdSSH

bsdSSHを指定する。これで、ワンショットでSSH出来るカーネルが上がってくる。何も指定 しなければ、5秒後に、bsd(gdbでマクロが見られるやつ)が、普通に立ち上がる。

リピーターの観光

一回旅行をすると、OpenBSDのフレンドリィーさが身に染みて分かってくる。そうすると、何度も訪れたくなるのは、チャイナの人と一緒。お上りさんじゃなくて、目的を持って旅をしたい。 で、選んだのは、オーディオなボードを検出して、それがカーネルに組み込まれる現場の確認。

カーネル屋さんなら、そりゃドライバーの組み込みでしょって言うはず。組み込むボードは、追加でac97をqemuの起動部分に追加した。(フィジカルには、オーディオボードの2枚刺しだ)

  -soundhw ac97,es1370

組み込みなんで、アタッチかな。

(gdb) b audio_attach
Breakpoint 1 at 0xd04348da: file /usr/src/sys/dev/audio.c, line 993.
(gdb) c
Continuing.

Breakpoint 1, audio_attach (parent=0xd17dca00, self=0xd17dcc00, aux=0xd0ea8b18) at /usr/src/sys/dev/audio.c:993
993     {

予想は当たって、BPが当たったよ。以下は、長い長いルートを通って、やっと許可された図(ファイル名を閲覧し易いように、関数の引数は削除した)

(gdb) bt
#0  audio_attach (..) at /usr/src/sys/dev/audio.c:993
#1  0xd075f6b9 in config_attach (..) at /usr/src/sys/kern/subr_autoconf.c:401
#2  0xd075f341 in config_found_sm (..) at /usr/src/sys/kern/subr_autoconf.c:311
#3  0xd0434e5c in audio_attach_mi (..) at /usr/src/sys/dev/audio.c:1185
#4  0xd08b8940 in auich_attach (..) at /usr/src/sys/dev/pci/auich.c:524
#5  0xd075f6b9 in config_attach (..) at /usr/src/sys/kern/subr_autoconf.c:401
#6  0xd075f341 in config_found_sm (..) at /usr/src/sys/kern/subr_autoconf.c:311
#7  0xd06153fb in pci_probe_device (..) at /usr/src/sys/dev/pci/pci.c:557
#8  0xd0615b15 in pci_enumerate_bus (..) at /usr/src/sys/dev/pci/pci.c:784
#9  0xd0614573 in pciattach (..) at /usr/src/sys/dev/pci/pci.c:197
#10 0xd075f6b9 in config_attach (..) at /usr/src/sys/kern/subr_autoconf.c:401
#11 0xd075f341 in config_found_sm (..) at /usr/src/sys/kern/subr_autoconf.c:311
#12 0xd058cc95 in mainbus_attach (..) at /usr/src/sys/arch/i386/i386/mainbus.c:250
#13 0xd075f6b9 in config_attach (..) at /usr/src/sys/kern/subr_autoconf.c:401
#14 0xd075f3cf in config_rootfound (..) at /usr/src/sys/kern/subr_autoconf.c:326
#15 0xd0912cb4 in cpu_configure () at /usr/src/sys/arch/i386/i386/autoconf.c:160
#16 0xd0696d9e in main (framep=0x0) at /usr/src/sys/kern/init_main.c:370
(gdb)

そして、こちらは、dmsgに出てきた記録。

auich0 at pci0 dev 4 function 0 "Intel 82801AA AC97" rev 0x01: apic 0 int 11, ICH
ac97: codec id 0x83847600 (SigmaTel STAC9700)
audio0 at auich0

後は、これを手掛かりに、思い出に浸るのが定番。ゆっくりグラスでも傾けながらね。