xv6-armv7 (7)
世はまさに錦秋。市場には銀杏が出てきた。これって食べ過ぎると毒になるらしい。一度に 10粒ぐらいですかね? 居酒屋で出てくるのは何粒でしたっけ? 後で調べてみよう。
秋と言えば読書週間。図書館主催のブックリサイクルが開かれていた。不用になった本を 持ち寄って交換しましょって市。勿論無料。無料に目が無い女房の命令で出陣。
去年も出てみたけど、オイラーの趣味に合う本は皆無だったんだよなー。 そんな訳で、オイラーは図書館に非難して、そこで待ち合わせする事にした。
暇なのでいつもは立ち入らないエリアを覗いてみたよ。ったって、レンタルDVD屋みたいに ノレンがかかったエリアじゃないけどね。そう言えば、某レンタル屋が運営してる(してた) 図書館は、ノレンエリアは有ったんでしょうか? 非常に気になるぞ。
で、そこは児童青少年書のエリアでした。楽しい本、みっけた。『なぜ数学を学ぶのか』、『将棋とチェスの話』 いずれも岩崎ジュニア新書。ジュニアって何歳ぐらいまでを言うの? ちょい疑問。
数学本に、数学なんて勉強して意味あんの?を主張する女子高生が出てきて、数学の先生と 対決するって舞台設定だった。ジュニアってのは、高校生ぐらいの年代までなのか。
で、女子高生曰く、2/3 ÷ 1/4 って、分子と分母をひっくり返して掛け算すれば、答えが 出るけど、この割り算って一体、どゆ事? こう改まって聞かれるとオイラー返答出来ないな。 だめ親父ですよ。 こういう楽しい話が一杯出て来るんで為になるな。
将棋やチェスは、戦争シュミレーションゲームとか。確かに、その通りだな。王様を追い詰めた 方が勝ちって確かにそうだ。攻める途中で、相手の駒を取ると、その駒はもう二度と使えないのが チェス。これは相手を殺すって意味。将棋は、捕虜にして、そいつを自分の戦闘員にしちゃうってルール。 殺戮しまくるか、有効利用するか、西と東で大違い。こういうみかたもあるんだな。
日本が戦争に負けてGHQが乗り込んできた時、将棋連盟の人がGHQに呼ばれて査問を受けたとか。 日本の将棋は、戦争に捕虜を使役する、これは捕虜虐待ではないか? これに対して、捕虜を元の階級で 優遇して再就職の機会を与えるのだと反論。
そうかと思うと、チェスは民主的だ。ちゃんと女性まで戦争に参加している。これに対し、 日本は女性を野戦には連れていかない。女王を楯にしてキングが逃げ出すような事は無い。 こういう話がわんさか出てくる。
将棋ときたら次は碁でしょう。新書には無かった。別の棚に、将棋の本と囲碁の本が沢山 置いてあった。一時は『ひかるの碁』なんてのが流行ったからねえ。初めてでもよく分かる 囲碁なんてのを手に取ってみた。こちらは、陣取り合戦のシュミレーションですな。
定石が沢山出てくる。碁石って碁筒の中に沢山入ってるけど、一体幾つ入ってるの? 白が180個で黒が181個だそうだ。黒先行なんで、一つ多いのかな? 将棋やチェスは、 マスの中に駒を入れるけど、碁は、交点に石を置いて行く。座標上の点、、、、って事で、 なんとなく碁の方が数学寄りの気がするのは、オイラーだけかな。白黒しか無いのも より数学っぽい。それに、将棋では駒を無くして大騒ぎしたり、しょうがないのでコインや ボタンで代用したりがあるようだ。囲碁は、その点楽だね。
囲碁の初心者が半年くらいで5級になる方法 こんなのを見つけた。GNUでgoを扱っているそうだ。どんな風になってるの 定石に則って、手を出してくるのだろうな。なんか定石ってパターンマッチングのような 気がするぞ。定石は数万あるそうだけど、コンピュータの馬鹿力で、くまなく調べている んだろうな。でも、囲碁は将棋よりもずっとコンピュータ化が難しいらしい。 どんなコードになってるか、眺めてみるかな。
pkg
折角 NetBSDを入れたんだから、少しはアプリも入れておこうと思った。pkgsrcから コンパイルかなってんで、とあるpkgの所を開いたら
nb7$ ls CVS/ PLIST.DragonFly PLIST.common patches/ DESCR PLIST.Linux distinfo Makefile PLIST.NetBSD options.mk
PLISTって確か、pkgのパッキングリストだったはず。共通のcommonが有って、それぞれ向けに DragonFlyとかLinuxとか、ここには出てこないけど、cocoaとかminix3なんてのも有る。 各OS向けなんだな。そうか、NetBSDのパッケージング技術は、世界のOSが認めたんだな。 Linuxのdebだとかrpmなんてのは、Linux島のローカル仕様って事だね。
で、お目当てのemacsでもと思ってMakefileをちらっと覗いてみると
USE_TOOLS+= autoconf automake gmake makeinfo gzip
コンパイルするのに、こういう道具が必要とな。これらの道具だけで済めばいいんだけど、 道具を作る為には別の道具や下手するとperlやらpythonやらが必要になる事が往々にしてある。 たった一度の使用のために、いろいろ作らされるのは気に喰わんな。
こうなったら、野良インストールしよう。ソースはwgetを使って取ってくるか。そんなアプリはi386用にパッケージング されていない。それじゃw3mは? それも無い。それじゃ、FreeBSD様ご愛用のfetchは? それも無い。でも、man fetchしたら
FETCH(3) Library Functions Manual FETCH(3) NAME fetchMakeURL, fetchParseURL, fetchCopyURL, fetchFreeURL, fetchXGetURL, fetchGetURL, fetchPutURL, fetchStatURL, fetchListURL, fetchXGet, fetchGet, fetchPut, fetchStat, fetchList, fetchXGetFile, fetchGetFile, fetchPutFile, fetchStatFile, fetchListFile, fetchXGetHTTP, fetchGetHTTP, fetchPutHTTP, fetchStatHTTP, fetchListHTTP, fetchXGetFTP, fetchGetFTP, fetchPutFTP, fetchStatFTP, fetchListFTP fetchInitURLList, fetchFreeURLList, fetchUnquotePath, fetchUnquoteFilename, fetchStringifyURL, fetchConnectionCacheInit, fetchConnectionCacheClose, fetch -- file transfer functions LIBRARY File Transfer Library (libfetch, -lfetch)
つらつら見てくと、ftpの項目もミレってご案内。なんとftpが拡張されてて、wgetのように 使える事が判明。素晴らしい。これで、curlもwgetも取りあえず不用だな。
emacs
最小の構成でいいな。
nb7$ ./configure --with-x=no --with-x-toolkit=no \ --with-jpeg=no --with-png=no --with-gif=no --with-tiff=no
どうせターミナルに貼り付けて使うだけだから、Xとか絵の関係は落としました。 その結果、こんな構成で作るぜいって報告がありましたよ。
Configured for `i386-unknown-netbsdelf7.0'. Where should the build process find the source code? . What compiler should emacs be built with? gcc -std=gnu99 -g3 -O2 Should Emacs use the GNU version of malloc? yes Should Emacs use a relocating allocator for buffers? yes Should Emacs use mmap(2) for buffer allocation? no What window system should Emacs use? none What toolkit should Emacs use? none Where do we find X Windows header files? NONE Where do we find X Windows libraries? NONE Does Emacs use -lXaw3d? no Does Emacs use -lXpm? no Does Emacs use -ljpeg? no Does Emacs use -ltiff? no Does Emacs use a gif library? no Does Emacs use a png library? no Does Emacs use -lrsvg-2? no Does Emacs use imagemagick? no Does Emacs support sound? yes Does Emacs use -lgpm? no Does Emacs use -ldbus? no Does Emacs use -lgconf? no Does Emacs use GSettings? no Does Emacs use a file notification library? no Does Emacs use access control lists? no Does Emacs use -lselinux? no Does Emacs use -lgnutls? no Does Emacs use -lxml2? no Does Emacs use -lfreetype? no Does Emacs use -lm17n-flt? no Does Emacs use -lotf? no Does Emacs use -lxft? no Does Emacs directly use zlib? yes Does Emacs use toolkit scroll bars? no
コンパイルにはgnu特製のmakeが必要になるかと構えていたら、BSD系のmakeでもOkって事 みたいで、すんなりといきました。
166.85s real 77.54s user 84.03s system
裸のemacsだと、こんなコンパイル時間で済んじゃうですかね。拍子抜けしました。尤も、ほとんど lispを作るだけですから、こんな時間でOKだったとも言えるな。
所で、コンパイル時に指定された、-g3って何だろう?それにmakeが素直に使えたのは、 ひょっとして、GNU makeを取り込んでいないか?
ーgの方は、debug情報の密度のようだ、指定する数字が大きいほど、いろいろなdebug情報が 付加されるとな。
makeの方は、manを引いてみると
HISTORY A make command appeared in Version 7 AT&T UNIX. This make implementation is based on Adam De Boor's pmake program which was written for Sprite at Berkeley.
由緒ある出なんだな。emacsもBSD界へ拡販のため、敷居を下げたんだな。
インストールの方は
139.06s real 21.70s user 78.52s system
こんなもので済んじゃった。案ずるより産むが易しだな。と故事を書いたけど云われを 知らなかったんで調べたよ。そしたら『案じるより団子汁』なんてのも出てきた。 くよくよしたってなるようにしかならないんだから、団子汁でも食べて気楽に待つのがよい って事らしい。ラテン系、人生達観してますなあ。こうでなくっちゃ!
出来上がったものを確認しておく
nb7$ ldd /usr/local/bin/emacs-24.5 /usr/local/bin/emacs-24.5: -lossaudio.1 => /usr/lib/libossaudio.so.1 -lgcc_s.1 => /usr/lib/libgcc_s.so.1 -lc.12 => /usr/lib/libc.so.12 -lexecinfo.0 => /usr/lib/libexecinfo.so.0 -lelf.1 => /usr/lib/libelf.so.1 -lterminfo.1 => /usr/lib/libterminfo.so.1 -lpthread.1 => /usr/lib/libpthread.so.1 -lm.0 => /usr/lib/libm.so.0 -lz.1 => /usr/lib/libz.so.1
対する、fedoraのemacsは
[sakae@fedora xv6-armv7]$ ldd /usr/bin/emacs-24.5 | wc -l 120
余りに色々なものを詰め込んでいるんで、サマリーだけ。emacsはよく十徳ナイフに 例えられるけど、ちょっと肥大しすぎていないかい。まあ、それが売りって言われれば それまでだけど。emacsを入れるとctags/etagも付いてくるんで、次回からは、Linuxでも 自前でコンパイルするかな。
所で、ebrowse なんて言う見知らぬアプリも出来ていた。これは何? 初めてみるぞ。 聞いてみた。ebrowseパッケージとは Cフラフラ用みたい。あえて使うなら、どんな構造体が在るか、そのメンバーはどうなってるか 一覧出来る事かな。プログラム解析の初期の段階で眺めるには便利だろう。
ちょいと使い方をメモしとく。
sakae@uB:~/xv6-armv7/src$ ebrowse *.h *.c
これで、直下にBROWSEってファイルが出来る。後は、これをemacsから開く。 見たい構造体の所へカーソルを合わせて、スペースを叩くと、その構造体が表示される。 元に戻るには、q。冒頭に、スペースの代わりに、L v すると、画面が割れ、 全ての構造体のメンバー名を確認出来る。窓間の移動はTABキー。*Globals* は、グローバル 変数をリストしてくれる。
emacsclientのも有るぞ。どうやって使う? emacsclientを使ってEmacsの起動を速くする
alias emacs='emacsclient -nw -a ""'
こう書いておくと、emacsがだえもん君として居座ってくれる。このだえもん君を殺す方法は、pkill emacs。 居座りモードをカットして起動するには、emacs ってな具合に、アィリアスを無効に してあげればよい。
もう一つemacsの付属品が有った。grep-changelog なんてのが。emacsから CTL-x 4 a で 簡単にChangelogを開いて書けるようになってるんだけど、それの検索用アプリとの事。 使い方は、Unixのメモ技術をミレ。懐かしい記事だよ。
上のemacsだえもんモードを使うと、一番最初に起動した時のcurrent working directoryをずっと覚えていて、 elacsclient起動時に、そのdirをhomeと思っちゃうみたいだ。changelogの実験をしてて、 ファイルを作ったのはいいけど行方不明になり、探したら、一番最初の起動時のdirに鎮座 してた。帰巣本能が有るって便利だか不便だか? 時と場合によるな。
デバドラ
前回、トップハーフとかボトムハーフなんて言い回しが在るって書いた。それらの言葉で 検索してたら、出てきたのがこれ。 Linuxデバイスドライバ開発入門。なんかハロワ攻略本に 通じるものがあるなあと思いながら読んでますよ。
読んだ結果、これってFreeBSDのローダブルモジュールじゃねぇって思ったぞ。kldload hoge.ko とかやるやつね。探ってみる。
OpenBSDやNetBSDはカーネルが一枚板になってるんで、後から動的に貼り付けたり、取り外したり って機能はサポートされていない。OSの機能を変更するなら、configいじってコンパイルしろって 頑なに守ってますね。
ああ、NetBSDの/usr/src/sysの下を見てたら、何やらmodulesなんてのが有るぞ。 LKM がサポートされたのかな? 7.0の売りでluaとか言ってるし。今度調べてみよう。
再び console
前回はshからの標準入出力の一端を見たけど、まだ不完全燃焼。console.cを見ると、 consolereadとかconsolewriteを見ていなかったから。これらは何時使われるのだろう?
同ファイル中で、consolereadとかを参照してるのは、以下の部分
284void consoleinit (void) 285{ B28 initlock(&cons.lock, "console"); 287 initlock(&input.lock, "input"); 288 289=> devsw[CONSOLE].write = consolewrite; 290 devsw[CONSOLE].read = consoleread; 291 292 cons.locking = 1; 293}
(gdb) bt #0 consoleinit () at console.c:289 #1 0xc0024898 in kmain () at main.c:42 #2 0x800104e8 in start () at start.c:195 Backtrace stopped: previous frame inner to this frame (corrupt stack?)
OS起動中の一環として呼ばれるんですねぇ。そしてイニシャライズを終了すると
(gdb) p devsw[1] $5 = { read = 0xc0021df8 <consoleread>, write = 0xc0021f84 <consolewrite> }
このように、デバイスの動作が登録されるとな。上でみたFreeBSDのデバドラで言うと、 モジュールのロードが成功した段階ですかね。勿論、xv6はデバイスは固定だから、こういう風に、 ハードコーディングしてある訳だ。NetBSD相当と言った所かな。
uv6で該当する所を探してみると、conf.hに次のようなのがあった。
/* * Character device switch. */ struct cdevsw { int (*d_open)(); int (*d_close)(); int (*d_read)(); int (*d_write)(); int (*d_sgtty)(); } cdevsw[];
一般化すると open close read write そしてsgttyか。五原則といった所だな。 cdevswってわざわざ断ってるのは、ブロックデバイス用も有るからだ。
今度は、consolereadとconsolewriteにBPを貼り、shからwc UNIXしてみました。リターンを 叩くと、早速consolereadに引っかかってきましたよ。
(gdb) bt #0 consoleread (ip=0xc00ac55c <icache+132>, dst=0x4fc3 "w\001", n=1) at console.c:223 #1 0xc0023970 in readi (ip=0xc00ac55c <icache+132>, dst=0x4fc3 "w\001", off=514, n=1) at fs.c:468 #2 0xc0022884 in fileread (f=0xc00abb28 <ftable+52>, addr=0x4fc3 "w\001", n=1) at file.c:117 #3 0xc00264a8 in sys_read () at sysfile.c:87 #4 0xc00261cc in syscall () at syscall.c:154 #5 0xc0027724 in swi_handler (r=0xc7fdffb8) at trap.c:12 #6 0xc00275a8 in trap_swi () #7 0x000015c4 in ?? ()
shのgetsからの呼び出しでしょう。前回の、よりハード側と結び付いたルーチン、consoleintr内に 次の部分があります。
while ((c = getc()) >= 0) { switch (c) { : default: if ((c != 0) && (input.e - input.r < INPUT_BUF)) { c = (c == '\r') ? '\n' : c; input.buf[input.e++ % INPUT_BUF] = c; consputc(c);
一文字読み込んで、その文字が特殊文字(一文字削除等)でなかったら、default句が実行される。 その中で、input.bufという配列に、文字を取り込んでる。配列をリングバッファーとして 扱ってますね。
(gdb) p input $4 = { lock = { locked = 0, name = 0xc002980c "input", cpu = 0x0, pcs = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, buf = "ls\nwc UNIX\n", '\000' <repeats 500 times>, r = 10, w = 11, e = 11 }
UNIXのXを読み終わって、contすると、今度は
(gdb) bt #0 consolewrite (ip=0xc00ac55c <icache+132>, buf=0x3f1b "4\001", n=1) at console.c:269 #1 0xc0023b80 in writei (ip=0xc00ac55c <icache+132>, src=0x3f1b "4\001", off=521, n=1) at fs.c:501 #2 0xc00229c0 in filewrite (f=0xc00abb28 <ftable+52>, addr=0x3f1b "4\001", n=1) at file.c:166 #3 0xc0026548 in sys_write () at sysfile.c:100 #4 0xc00261cc in syscall () at syscall.c:154 #5 0xc0027724 in swi_handler (r=0xc7fe4fb8) at trap.c:12 #6 0xc00275a8 in trap_swi () #7 0x000007dc in ?? ()
wcの出力をする為に、consolewriteが呼ばれ始めました。consolewriteの引数として渡って くるiノードを確認すると、確かにconsoleデバイスになってました。
(gdb) p *ip $9 = { dev = 1, inum = 18, ref = 1, flags = 3, type = 3, major = 1, minor = 1, nlink = 1, size = 0, addrs = {0 <repeats 13 times>} }
一段フレームを上がって、writeiを見ると、それは、fs.cに定義されてました。
496 if (ip->type == T_DEV) { 497 if (ip->major < 0 || ip->major >= NDEV || !devsw[ip->major].write) { 498 return -1; 499 } 500 501=> return devsw[ip->major].write(ip, src, n); 502 }
consoleinitで登録しておいたconsolewriteが、こんな所で使われていました。コンソールって メジャーなデバイスなんですな。なお、この関数の後半部分はブロックデバイス(disk)の サービスを行っているように見受けられました。
ちょいと疑問
上記でconsoleへの入力文字はグローバル構造体 inputの中のbufに溜め込まれる。端末が 複数ある場合はどうなるの? それから、デバイスファイルを作る時に指定した、major、minorの うち、minorが有効活用?されていない。majorは、機器共通の挙動をまとめる時の番号、 minorの方は、共通機器の中の個別の機器を特定するのに使うって説明だった。
モデムが複数台、マシンに繋がってるような場合、モデムと言うかシリアルラインの挙動は 同一、だから同じドライバーが使える。一方、line1とかline2とかで、個々のモデムを識別 するのにminor番号を使うって事。
こういう時は、uv6本を見るに限る。kl.c/klopenを見れって事らしい。通常/etc/initから 呼び出される端末初期化手続きとな。(446ページ参照)
23struct tty kl11[NKL11+NDL11]; 41 tp = &kl11[dev.d_minor]; 42 if (u.u_procp->p_ttyp == 0) { 43 u.u_procp->p_ttyp = tp; 44 tp->t_dev = dev; 45 }
tty構造体の中にxv6で言うinput.buf 相当も部分が含まれている。kl11はtty構造体の 配列。これをminor番号で指定してる。一方、tty構造体は、tty.hに定義されてて
16/* 17 * A tty structure is needed for 18 * each UNIX character device that 19 * is used for normal terminal IO. 20 * The routines in tty.c handle the 21 * common code associated with 22 * these structures. 23 * The definition and device dependent 24 * code is in each driver. (kl.c dc.c dh.c) 25 */ 26struct tty 27{ 28 struct clist t_rawq; /* input chars right off device */ 29 struct clist t_canq; /* input chars after erase and kill */ 30 struct clist t_outq; /* output list to device */ 31 int t_flags; /* mode, settable by stty call */ 32 int *t_addr; /* device address (register or startup fcn) */ 33 char t_delct; /* number of delimiters in raw q */ 34 char t_col; /* printing column of device */ 35 char t_erase; /* erase character */ 36 char t_kill; /* kill character */ 37 char t_state; /* internal state, not visible externally */ 38 char t_char; /* character temporary */ 39 int t_speeds; /* output+input line speed */ 40 int t_dev; /* device name */ 41};
上記で28-29行の部分が、input.bufに相当する。uv6では、これらの端末が幾つ繋がるか、 conf/mkconf.cを走らせてconf.cを生成するのかな。
そのあたりOpenSDでどうなってるかと言うと、設定ファイルが /etc/ttysに有る。 uv6とは違ってttyデバイスをたっぷりと用意(無駄に100個も)し、使う物を選んでクレイって作戦。
# # $OpenBSD: ttys,v 1.18 2008/01/09 17:39:42 miod Exp $ # # name getty type status comments # console "/usr/libexec/getty std.9600" vt220 off secure ttyC0 "/usr/libexec/getty std.9600" vt220 on secure ttyC1 "/usr/libexec/getty std.9600" vt220 off secure :
statusでonになってるやつが活線化される。ttyC0が使えるようにした。
[ob: ~]$ ps awx|grep ttyC0 19214 C0 Is+ 0:00.05 /usr/libexec/getty std.9600 ttyC0
gettyは、活線化された端末からlogin出来るようにするアプリだ。昔風の仕組みに なってて実に分かりやすい。その点リナの方はどうだ。昔のリナは、/etc/inittabだかで 設定させてたはずだけど、今じゃオイラーにはワケワカメな仕組みに変更されちゃってる。
GETTY(8) System Manager's Manual GETTY(8) NAME getty ? set terminal mode SYNOPSIS getty [type [tty]] DESCRIPTION The getty program is called by init(8) to open and initialize the tty line, read a login name, and invoke login(1). The argument tty is the special device file in /dev to open for the terminal (for example, ttyh0). If there is no argument or the argument is ‘-’, the tty line is assumed to be open as file descriptor 0.
[ob: ~]$ ls -l /dev/ttyC* crw------- 1 root wheel 12, 0 Nov 5 17:05 /dev/ttyC0 crw------- 1 root wheel 12, 1 Jun 19 05:27 /dev/ttyC1 :
grep-find
emacsのgrepを調べていて、grep-findなんていうコマンドを知った。このコマンドを起動 すると、 minibufferに下記のように聞いてくるので、カーソルの有る位置に検索語(下記の例だとminor)を 入力する。
Run find (like this): find . -type f -exec grep -nH -e minor {} +
emacs君は、こんな合わせ技を知ってるのね。で、検索をかけると画面が割れて、結果が 表示される。カーソルを検索画面に移動して、見たい所でnを押すと、その周辺部分が 元画面に表示される。nを叩くたびにその周辺を表示してくれるので、これなかなか便利。 nの他にpも使えるよ。
emacs君の合わせ技の最後に付いてるプラス記号は何? マンセー。
-exec command {} + アクション -exec のこの変形も、選択したファイルに対して指定した コマンドを実行するが、 コマンドラインを形成するとき、選択した各 ファイル名をコマンドラインの末尾に 追加して行くという方法を取る (訳注: コマンドラインが長くなりすぎるときは、 処理するファイル名 の数を適切に分割して、コマンドを複数回実行する)。 そのため、コマ ンドを呼び出す回数は、マッチしたファイルの数より ずっと少なくて すむわけだ。コマンドラインの形成法は、 xargs のコマンドライン形 成法とほぼ同じである。`{}' はコマンドライン中の 一ヶ所でしか使え ない。コマンドは find を実行したディレクトリで実行される。 (訳 注: `+' は引き数なので、直前の引き数との間に空白が必要だ という ことに注意してほしい。)
execオプションよりもexecdirの方が安全らしい。ふーーーん。 そして、バイナリーファイルとかにgrepを適用を止めるには、execの代わりにokを 使って選択出来るとな。めんどくさい事になりそうだ。