Xv6

年始早々、三日坊主フラグが立ってしまった、Scalaだけど、先方はやっきになって新しい scala 2.10が出たから、試して みんしゃいと仰る。さてどうすべ? ずるずると新しいのに引かれてやって行くか。 そうなると、clojureの二の舞になりそうだな。

Scalaやclojureみたいに進化が激しいものは、本が出てもすぐに陳腐化してしまう。 使っている版を上げなければいいんだろうけど、女房と畳は新しい方が良いのたとえ通りに 、新しいのに飛びつきたくなるんだ。

日本で唯一のclojure本も新しい版に合わせたものが出るらしいけど、多分それも、いたちごっこ になるんだろうな。

clojureと言うとその上で動く、Incanterなんてのが有った事をふと思い出したよ。 良いアプリケーションが無いと、言語系は流行らないからなあ。熱烈な応援団が必要よ。 こちらの方は熱烈な応援者かな。

Windowsに入ってるJavaは使い道が無いので、Incanterで使ってみるかな。jarファイル一つで clojureも付いてくるしね。 Web系女子がLispに出会って統計学に目覚めるまでのお話 なんてのも書いておられるようなんで、楽しそう。

unix v6

もう去年の事になるが、 はじめてのOSコードリーディング ――UNIX V6で学ぶカーネルのしくみ という本が出たようだ。 (出版のいきさつとかはこちらから辿れる) おいらはこの本の先祖本を持ってて、過去にこのOSを動かした事がある。 懐かしいなあ。

この他のOS本と言うと、Linuxが誕生するきっかけとなった、minix本もあるな。教育目的で、大学の 教授が開発してたんだな。ソースを読んだけど、先進的な作りで何が何やらちっとも分からんかったなあ。

xv6

最近、某所で Xv6, a simple Unix-like teaching operating system なんてのが有る事を知った。MIT初(発)の教育用OS。minixはヨーロッパ生まれなんで、負けて なるものかと対抗意識丸出しと言う構図でしょうか?

こういう下衆の勘ぐりはともかくとして、開発のいきさつ等はこちらのページ に詳しく解説されています。

PDP-11からX86へ進化させたようですが、今はARMだろうって思われているかも知れません。 もう有志の方がやっておられますね。

能書きはともかく、早速動かしてみます。gitで取ってきて、READMEを熟読。 ふむ、いろいろなOSが協力してんのね。Linuxからコードの寄贈が無いって事はなかなか意味深長 だなあ。移植性に優れた綺麗なコードが採用されてるってか。

FreeBSDで動くって書いてあったけど、しょっぱなのコンパイルでコケテしまったので、安易に ArchLinuxでやる事にします。

[sakae@arch xv6]$ make qemu
   :
qemu -serial mon:stdio -hdb fs.img xv6.img -smp 2 -m 512
QEMU 1.2.1 monitor - type 'help' for more information
(qemu) QEMU 1.2.1 monitor - type 'help' for more information
(qemu)
Could not initialize SDL(No available video device) - exiting
make: *** [qemu] Error 1

どうやら、Xを上げて、そこでやらないとQEMUのお気に召さないようです。lxdeを動かして そこでやったら動きましたよ。画面が2つ出てくるのね。

でも、X環境って好きではないおいらはコンソール環境でやりたいな。Makefileを見てたら そういう人にもちゃんと対応してくれてる事を発見。

[sakae@arch xv6]$ make qemu-nox
qemu -nographic -hdb fs.img xv6.img -smp 2 -m 512
QEMU 1.2.1 monitor - type 'help' for more information
(qemu) QEMU 1.2.1 monitor - type 'help' for more information
(qemu)
xv6...
cpu1: starting
cpu0: starting
init: starting sh
$ ls
.              1 1 512
..             1 1 512
README         2 2 2507
cat            2 3 10544
echo           2 4 10013
forktest       2 5 6541
grep           2 6 11884
init           2 7 10342
kill           2 8 10005
ln             2 9 9995
ls             2 10 11707
mkdir          2 11 10074
rm             2 12 10067
sh             2 13 18475
stressfs       2 14 10549
usertests      2 15 40448
wc             2 16 10878
zombie         2 17 9787
console        3 18 0
usertests.ran  2 19 0

haltとかのシステムを止めるコマンドはサポートされてないんで、終了はQEMUをkillすると いう原始的な方法を取らざるを得ません。

Makefileを覗いてて、gdbからも使える事を発見。

[sakae@arch xv6]$ make qemu-nox-gdb
dd if=/dev/zero of=xv6.img count=10000
10000+0 records in
10000+0 records out
5120000 bytes (5.1 MB) copied, 0.078926 s, 64.9 MB/s
dd if=bootblock of=xv6.img conv=notrunc
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.002453 s, 209 kB/s
dd if=kernel of=xv6.img seek=1 conv=notrunc
279+1 records in
279+1 records out
143124 bytes (143 kB) copied, 0.00456256 s, 31.4 MB/s
*** Now run 'gdb'.
qemu -nographic -hdb fs.img xv6.img -smp 2 -m 512  -S -gdb tcp::26000
QEMU 1.2.1 monitor - type 'help' for more information
(qemu) QEMU 1.2.1 monitor - type 'help' for more information
(qemu)

こんな風に起動しておいて、別端末からgdbを起動してあげます。

[sakae@arch xv6]$ gdb -x .gdbinit kernel
GNU gdb (GDB) 7.5.1
 :
Reading symbols from /home/sakae/xv6/kernel...done.
warning: File "/home/sakae/xv6/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
        add-auto-load-safe-path /home/sakae/xv6/.gdbinit
line to your configuration file "/home/sakae/.gdbinit".
To completely disable this security protection add
        set auto-load safe-path /
line to your configuration file "/home/sakae/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
        info "(gdb)Auto-loading safe path"
+ target remote localhost:26000
warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default i8086 settings.

The target architecture is assumed to be i8086
[f000:fff0]    0xffff0: ljmp   $0xf000,$0xe05b
0x0000fff0 in ?? ()
+ symbol-file kernel

gdbを起動すると、.gdbinitを呼んでくれるはずなんだけど、7.5.1版では面倒な事を言ってくる んで、強制的に読ませました。

後は、アメリカの大学生の宿題のあんちょこ Homework: running and debugging xv6 に、習ってみます。

(gdb) b exec
Breakpoint 1 at 0x80100b08: file exec.c, line 12.
(gdb) c
Continuing.
[New Thread 2]
[Switching to Thread 2]
The target architecture is assumed to be i386
=> 0x80100b08 <exec>:   push   %ebp

Breakpoint 1, exec (path=0x1c "/init", argv=0x8dfffe98) at exec.c:12
12      {
(gdb) c
Continuing.
=> 0x80100b08 <exec>:   push   %ebp

Breakpoint 1, exec (path=0x8c9 "sh", argv=0x8dffee98) at exec.c:12
12      {
(gdb) c
Continuing.

最初にinitが呼ばれてプロセスが誕生。続いて人類との対話用にshellが動くのね。

^C
Program received signal SIGINT, Interrupt.
=> 0x80104737 <scheduler+122>:  nop
scheduler () at proc.c:270
270             continue;
(gdb) source gdbutil
(gdb) printdesc main
type = data
  base = 0xece483e5  limit = 0x38955fff  AVL = 0  B = small (0)   DPL = DPL_USER (3)
(gdb) detach
Detaching from program: /home/sakae/xv6/kernel, Remote target
Ending remote debugging.

これは何かなあ? やっぱりソース嫁となるんでしょうか? それとも解説本を読めと なるんでしょうか。解説本はpdfになってるんで、得意のemacs上で読みたいな。

pdfto

解説本を(無理して)emacs上で読んでみた。これでアドビとも縁が切れるな。何に、アクロリーダー は進化に次ぐ進化で重いのなんの。正直嫌いなんだな。

でも、文字が小さくてちと老眼のおいらにはキツイな。拡大も出来んようだし。検索しようと すると、pdftotextを入れろって言ってくるし。何処にそんなの有るんだ? こういう時は、 doc-view.elに何か書いてないか調べるのがいいかな?

;; and `pdftotext', which comes with xpdf (http://www.foolabs.com/xpdf/) or
;; poppler (http://poppler.freedesktop.org/).

xpdfの総本山でpdftotextを探したけど見つからず。それに近いのって事でpdftohtmlなんてのが 有ったよ。これってひょっとしてpdfをhtmlにしてくれて、ブラウザーでどうぞ(読んでください) ってやつ? ええい、ものは試し入れてまえ。ひょいと入ったのは、ウブでした。

sakae@ubuntu:~$ mkdir xv6-book; cd xv6-book
sakae@ubuntu:~/xv6-book$ mv ../boo-rev6.pdf ./book.pdf
sakae@ubuntu:~/xv6-book$ pdftohtml -c -zoom 2.0 book.pdf
Page-1
  :
Page-92

pdfの一ページが、htmlとpngに分解されてぶちまけられるので、あらかじめdirを掘って から、そこで変換します。zoomが効くんで、標準より大きくしました。標準はzoomファクターが 1.5との事ですから、133%に拡大した事になるのかな。

後は、book.htmlをブラウザーで閲覧すれば、左側に各ページのリンク、右側に指定された ページの内容が表示されます。よかったね。と言いたい所ですが、余白がちょいと気に なりました。

テキストの世界なら、どこかを書き換えれば、余白を調整出来るに違いない。そう思って、 pngファイルとhtmlファイルを見比べてみました。

ほとんどのpngファイルは白紙。たまに図の入ったものが見受けられます。そうするとhtmlで pngの台紙に文字を埋め込んでいるんだな。そうすると鍵はhtmlに有りか。

<HEAD>
<TITLE>Page 1</TITLE>

<META http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<STYLE type="text/css">
<!--
	p {margin: 0; padding: 0;}	.ft00{font-size:38px;font-family:Times;color:#000000;}
	.ft01{font-size:34px;font-family:Times;color:#000000;}
	.ft02{font-size:22px;font-family:Times;color:#000000;}
-->
</STYLE>
</HEAD>
<BODY bgcolor="#A0A0A0" vlink="blue" link="blue">
<DIV id="page1-div" style="position:relative;width:1224px;height:1584px;">
<IMG width="1224" height="1584" src="book001.png" alt="background image"/>
<P style="position:absolute;top:452px;left:573px;white-space:nowrap" class="ft00"><b>xv6</b></P>
<P style="position:absolute;top:531px;left:266px;white-space:nowrap" class="ft01">a simple, Unix-like teaching operating system</P>
 :

これ、book-1.htmlの冒頭部分です。用紙の大きさはDIVタグの中に埋め込まれていて、各段落の 表示位置はPタグの中か。用紙の左上を基点に、topで縦方向、leftで横方向を指定してるんだろうな。 だったら、leftの値を書き換えちゃえ。

#!/usr/bin/ruby

OFF = 150  # Text move to left for N px

def conv(file)
  nf = open("temp", "w")
  IO.foreach(file) do |line|
    if line =~ /position:absolute.*px;left:(\d+)px;/
      nvs = ($1.to_i - OFF).to_s
      line.sub!("left:#{$1}px;", "left:#{nvs}px;")
    end
    nf.print line
  end
  nf.close()
  File.rename("temp", file)
end

Dir.glob("*.html").each do |hf|
  conv(hf)
end

これを通したら、文字の表示は左に寄ってくれました。(図と整合性が取れなくなるんで、ちと 醜いページもあるけど、余りたくさん図は入っていないので許す)

で、pdftohtmlを入れるとpdftotextとかも釣られて入ってきましたよ。気をよくしてFreeBSDの portsからもpdftohtmlを入れてあげました。こちらは、変換のしかたがちとウブのそれとは 属性の表示方法が異なっていました。(FreeBSDで使うなら、上記のスクリプトは少々変更が必要です)

まあ、こんな事で、遊ぶ準備は整いました。