プリンター on unix/v6
訳有りで田舎で避暑してきた。昼間は暑いけど(女房によれば、太陽に刺されるとか)日陰に 入るとそこはカリホーニアな塩梅。夜は窓を開けておくと寒いぐらいな別天地。 おいらだけ、先に帰ってきたんだけど、運転疲れもあって9時過ぎには寝たよ。
11時にお尻に汗を掻いて目が覚めちゃった。水を一杯飲んで再び寝床へ。クーラーをかけっ放し にしてるんだけど、不快。寝付けない。寝付けない。しゃーないナイトキャップするか。
冷凍庫から冷やした角とグラスを取り出してきてハイボールにした。何かつまみが無いと 胃に悪いよね。明朝食べる予定だったポテトサラダを先行評価。難しい本でも読めば、ブースト されるかもと思って、CQ誌にしては珍しく複雑な式が載ってる記事を読んだよ。
効果てきめんで、ふらふらしてきたので、再び寝床へ。あーあ、女房が楽しみにしてたハイボール 飲んじゃったよ。3倍返しで、マティウスやらマドンナを要求されるんかいな? 明日の朝食に 手付けちゃったよ。なんて考えているうちに、地球や天井が回り出したよ。あーー、いい気持ち。
こんな気分は何年ぶり? 酔った時は、深く深呼吸だな。きっと部屋一面がアルコール臭く なっているに違いないな。
nm もどき
前回、カーネルのコンパイルを行って、大局が掴めた。今回は落ち葉を拾っていく。(早く 秋が来ないかな)
unix/v6には、内蔵のnmコマンドが用意されてる。が、その結果を眺めようとしても画面が 流れてしまって、ちと不都合だ。sim コマンドの所で、set log mylogとかやって、ログを FreeBSDに残すって方法もあるんだけど、別の方法を考えてみる。
unix/v6界からFreeBSDへのチャンネルは、今の所 ddしかない。ddで、FreeBSDに仮想Tapeを 持ってきた場合、512Byte毎に、ヘッダーとフッターが入るんだった。まずはこれを除去せんとな。 Perlで書かれた、逆パターンのやつがあるんで、それを流用してしまおう。
#! /usr/local/bin/perl
# Delete 512Byte each header/footer
# Usage; delhf.pl < dump.tap > out-file
while(!eof(STDIN)){
read(STDIN, $dmy,4);
read(STDIN, $str, 512);
print $str;
read(STDIN, $dmy,4);
}
もうPerlで考えられなくなったので、これでいいのかしらん? まあ、これで、いらないものが除去出来たとしましょう。次は、車輪の再発明します。はい、nmです。 勿論、FreeBSDのそれは使えませんから、スクラッチから書きます。リハビリを兼ねて、rubyします。
#!/usr/local/bin/ruby
# List symbol section for a.out
# Usage; nm.rb a.out
def cv(flg)
case flg
when /00/ then rv = "u" # Undefine
when /01/ then rv = "a" # Absolute
when /02/ then rv = "t" # Text
when /03/ then rv = "d" # Data
when /04/ then rv = "b" # Bss
when /1f/ then rv = "f" # File name (0x1f == \037)
when /20/ then rv = "U" # ext Undefine (Global)
when /21/ then rv = "A" # ext Absolute
when /22/ then rv = "T" # ext Text
when /23/ then rv = "D" # ext Data
when /24/ then rv = "B" # ext Bss
else rv = "?" # Unknown
end
rv
end
## main
f = File.open(ARGV[0])
h = f.read(10).unpack("v*") # read header by vax order(little endian)
cnt = h[4]/12 # symbol entries count
f.seek(16 + h[1] + h[2]) # skip (header + text + data)
cnt.times do
name = f.read(8).unpack("Z8")[0]
flg = f.read(2).unpack("H2")[0]
val = f.read(2).unpack("v")[0]
printf("%s %9s %06o\n", cv(flg),name,val)
end
f.close
相手はバイナリーファイルなんで、unpack使いまくりです。アンパックのテンプレートに8進数を 処理するやつが無いのは、誰に文句を言えばよいのでしょうか?
動いているか確認します。unix/v6のカーネルにどんな名前が含まれているのかなあ? 興味が ありますよ。
[sakae@cdr ~/UV6]$ cat dump.tap | bin/delht.pl > a.out [sakae@cdr ~/UV6]$ bin/nm.rb a.out D trap 000746 D start 000422 D dump 000320 T call 020010 T _klrint 071100 : B _t_nxrec 041542 T _tcomman 073724 T _tmstart 074206 T _tmphys 075124
オリジナルとは多少フォーマットが違うけど、いいやね。
ラインプリンターを使う
マニュアルによると、使えそうなコマンドは、prとかoprがあります。実際に試す前に、お前 ラインプリンターなんて持ってないじゃんと言う、大問題に気づきました。が、それはそう simの力を借りて、FreeBSD界にファイルと言う形で結果を残す事に今決めました。simの 起動スクリプトに
att lpt paper.txt
なんてのを指定しておきます。(paper.txtは任意の名前です。へたれな名前ですが、ご勘弁を) で、実際に試してみると。。。
# pr rootList Aug 20 13:28 1994 rootList Page 1 total 294 -rw-rw-rw- 1 root 26127 Aug 20 13:13 CATLOG drwxr-xr-x 2 bin 1040 Jan 1 1970 bin drwxr-xr-x 2 bin 400 Aug 20 13:16 dev drwxr-xr-x 2 bin 304 Aug 20 13:27 etc drwxr-xr-x 2 bin 336 Jan 1 1970 lib drwxr-xr-x 17 bin 272 Jan 1 1970 mnt drwxr-xr-x 2 bin 32 Jan 1 1970 mnt2 -rwxrwxrwx 1 root 29302 Aug 20 13:24 myunix -rw-rw-rw- 1 root 28472 Aug 20 12:01 rkunix -rwxr-xr-x 1 bin 28636 Aug 20 11:38 rkunix.40 drwxrwxrwx 2 bin 144 Aug 20 13:27 tmp -rwxr-xr-x 1 bin 28472 Aug 20 12:01 unix drwxr-xr-x 13 bin 224 Aug 20 12:22 usr drwxr-xr-x 2 bin 144 Aug 20 13:28 usr2 # opr -lp rootList #
どうやら、prは整形してコンソールに出力するようでした。それなら、oprをばと思って 試してみるも、FreeBSD側には結果が残らず。はて、使い方が悪いのかしらん? こういう時は かなめのデバイスがあるかですね。/devの下をサルベージするも、lpなんてのはかすりも しませんでした。
じゃ、無いなら作るだけとばかり、作りましたよ。(lpは、キャラクターデバイスです)
# ls -l /dev/lp* crw-rw-rw- 1 root 2, 0 Aug 20 13:28 /dev/lp crw-rw-rw- 1 root 2, 0 Aug 20 13:16 /dev/lp0
最初に、lp0を作って試すもダメだったので、lpも作って試すと言う馬鹿をやちゃいました。 でも、動かんのですよ。これが。ならば、奥の手を出しますか。恐怖のデバイス直叩き。
# cat rootList > /dev/lp /dev/lp: cannot create
見事に怒られましたね。そんなデバイスは無いのかしらん?
Simulation stopped, PC: 021630 (MOV (SP)+,177776) sim> sh lpt LPT, address=17777514-17777517, vector=200, attached to paper.txt sim> e 200/4 200: 000000 202: 000000
simに落ちて、割り込みベクターを確認してみたよ。そしたら、見事にベクターが設定されて ないじゃないですか。これじゃ、動く訳ありませんな。これはもう、カーネルを作り直す しか。例の本には、unixのコンフィグレーションは、(某OSに比べて非常に)簡単よーー、 とか書いてますし。
sysの下にあるrunにlpを追加します。
mkconf rk tm tc lp : <--- Add done
そして、コンパイルし、出来たカーネルを /myunix として保存。起動時に、myunixを 指定してbootします。
PDP-11 simulator V3.8-1 Disabling XQ @myunix login: root # sync # Simulation stopped, PC: 002510 (MOV (SP)+,177776) sim> sh lpt LPT, address=17777514-17777517, vector=200, attached to paper.txt sim> e 200/4 200: 000276 202: 000200 sim> c
今度は、ちゃんとベクターが設定されますね。
# cat rootLisp > /dev/lp #
文句を言われずに、lpにデータが流れて行ったようです。FreeBSD側で確認してみます。
[sakae@cdr ~/UV6]$ cat paper.txt | head
total 294
-rw-rw-rw- 1 root 26127 Aug 20 13:13 CATLOG
drwxr-xr-x 2 bin 1040 Jan 1 1970 bin
drwxr-xr-x 2 bin 400 Aug 20 13:16 dev
drwxr-xr-x 2 bin 304 Aug 20 13:25 etc
drwxr-xr-x 2 bin 336 Jan 1 1970 lib
drwxr-xr-x 17 bin 272 Jan 1 1970 mnt
drwxr-xr-x 2 bin 32 Jan 1 1970 mnt2
-rwxrwxrwx 1 root 29302 Aug 20 13:24 myunix
-rw-rw-rw- 1 root 28472 Aug 20 12:01 rkunix
ちょいと余白が取られているのは、ラインプリンターっぽくていい感じです。この後 いろいろなファイルとかコマンドの結果をプリントしてみましたが、途中に改ページの マーク(^Lがそうです)が入ってて、いかにもな感じでしたよ。
ついでなので、オリジナルのnmの結果の一部も残しておきます。
002166T _pmode
003704T _printf
004566T _putchar^L 005402T _qs1
012632B _qscmp
012634B _qses
006130T _qsexc
再び simhで
折角プリンターを組み込んだので、動きを追ってみます。myunixなんで、生成途中でmkconfが 作ったl.sもオリジナルになってます。(例の本では、low.sとなってますが。)以下は、 その抜粋です。
. = 200^.
lpou; br4
. = 214^.
tcio; br6
. = 220^.
rkio; br5
. = 224^.
tmio; br5
//////////////////////////////////////////////////////
/ interface code to C
//////////////////////////////////////////////////////
.globl call, trap
.globl _klrint
klin: jsr r0,call; _klrint
.globl _klxint
klou: jsr r0,call; _klxint
.globl _clock
kwlp: jsr r0,call; _clock
.globl _lpint
lpou: jsr r0,call; _lpint
.globl _tcintr
tcio: jsr r0,call; _tcintr
.globl _rkintr
rkio: jsr r0,call; _rkintr
.globl _tmintr
tmio: jsr r0,call; _tmintr
PTP/PTRが無くて、LPとTMが登録されてます。それじゃ、プリンターの割り込みハンドラから 辿ってみます。
Simulation stopped, PC: 002510 (MOV (SP)+,177776) sim> e 200 200: 000276 sim> e 276/10 276: 004067 300: 000116 302: 057410 304: 004067 sim> e -m 276/10 276: JSR R0,420 302: BIS @4067(R4),(R0) sim> br -e 57410
割り込みベクターですから、動作としては、jmp @200 という事で、276番地から、ちょっと 表示してみました。-m を付けると逆アセンブルしてくれます。この結果、420番地は、Cの関数 callの開始番地。そこで、もう一度、次の番地が間接呼び出し(相当)される事になる。 最終的に呼び出される _lpintは、57410番地と判明したので、そこにブレークポイントを 設定した。
# cat l.s > /dev/lp Breakpoint, PC: 057410 (JSR R5,3574) sim> step 20 Step expired, PC: 000642 (MOV 2(SP),R1) sim> sh cpu history=20 PC PSW src dst IR 057410 030204|141622 057410 JSR R5,3574 003574 030204|057414 000304 MOV R5,R0 003576 030200|141566 057414 MOV SP,R5 003600 030210|000057 141566 MOV R4,-(SP) 003602 030200|000002 141564 MOV R3,-(SP) 003604 030200|067334 141562 MOV R2,-(SP) 003606 030200|003606 057414 JSR PC,(R0) 057414 030200|057414 057414 JSR PC,57346 057346 030200|141566 057346 JSR R5,3574 003574 030200|057352 057414 MOV R5,R0 003576 030200|141552 057352 MOV SP,R5 003600 030210|000057 141552 MOV R4,-(SP) 003602 030200|000002 141550 MOV R3,-(SP) 003604 030200|067334 141546 MOV R2,-(SP) 003606 030200|003606 057352 JSR PC,(R0) 057352 030200| BR 57374 057374 030200|057374 057374 BIT #200,@#177514 057402 030200| BNE 57354 057354 030200|057354 141542 MOV #120314,(SP) 057360 030210|057360 057360 JSR PC,@#642
これと、lp.cの該当部分を比べると。。
8976: lpint()
8977: {
8978: register int c;
8979:
8980: lpstart();
8981: if (lp11.cc == LPLWAT || lp11.cc == 0)
8982: wakeup(&lp11);
8983: }
最初に呼ばれている、3574番地は、レジスターの退避ルーチンか。でもって、 54346番地は、lpstartになるかな。こんな具合に、地図を埋めて いくのがいいのかな。なんだかジグソーパズルをやってるみたいで、面白いな。