V6 unix in okinawa
Upcoming SlideShare
Loading in...5
×
 

V6 unix in okinawa

on

  • 11,045 views

pdp11 unix lions

pdp11 unix lions

Statistics

Views

Total Views
11,045
Views on SlideShare
10,910
Embed Views
135

Actions

Likes
28
Downloads
279
Comments
0

10 Embeds 135

https://twitter.com 89
https://twimg0-a.akamaihd.net 14
https://si0.twimg.com 11
http://favtile.com 7
http://us-w1.rockmelt.com 6
http://bottlenose.com 2
http://twitter.com 2
http://www.plurk.com 2
http://a0.twimg.com 1
http://www.slashdocs.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

V6 unix in okinawa V6 unix in okinawa Presentation Transcript

  • オペ―レーティングシステムの読み書き Rev.2.1 @magoroku15 2012/3/24 日本Androidの会 沖縄支部 workshop@Naha Vol.17 - v6 unix 勉強会2012/3/24 1
  • 他人の作品を読まなかった偉 大な作家,他人の筆づかいを 研究しなかった偉大な画家, 同僚の肩越しに技を盗まな かった腕のよい外科医,副操 縦席で実地の経験を積まな かった767機長――果たして, そんな人たちが本当にいるの でしょうか? Dave Thomas著 Code Reading―オープンソースから学ぶソフトウェア開発技法 より2012/3/24 2
  • 最底辺活動 Lions本読書会に出てみた  本だけで読み解くのは大変  若干の解説を加えれば理解できる人は増えるはず  拙者のネタとしてGeekBarなどで話すことにした  これを最底辺活動と言っている ○ 他にもFPGAでPDP11を動かしたり、PICで遊んだり UNIX v6を読む理由  最新のBSD, Linuxと実装は異なるが根幹は同じ  UNIX v6を読む事が現代のOSを理解する近道(だと 思う)2012/3/24 3
  • Lions’ Commentary on UNIX本読書会 月に1回貸し会議室(喫茶室ルノアール)にあつまってLions本の読書会 濃すぎる常連@awazo 主催している人@7shi 低レイヤ勉強会を多数主催、SilverLightで動くPDP-11のエミュレータ作った人@xylnao11 古くからPDP-11とUNIXで遊んでて、最近安価なFPGAにPDP-11を載せてしまった人@superhoge Blogがすごい、JavaScriptで動くPDP-11のエミュレータを作った人@toyoshim 一人で読み終えてしまった人@pakuqi v7講座を生徒役で参加してBlogに話した事の10倍くらいの内容をまとめてくれた人@oraccha PDP11に詳しくて、V1も読んでる人2012/3/24 4
  • お勧めのBlogなど http://d.hatena.ne.jp/takahirox/ http://www.tom-yam.or.jp/2238/index.html http://d.hatena.ne.jp/n7shi/ http://xiangcai.at.webry.info/ http://d.hatena.ne.jp/oraccha/2012/3/24 5
  • @magoroku15の最近のネタ ADK互換モジュールを1200円で作る http://www.slideshare.net/magoroku15/poormans-adk-11350123 OpenCoresのw11を動かしてみる http://www.slideshare.net/magoroku15/pdp11-onfpga その他  横浜Android PF部,nagoyageekbar等で話したネタ は以下に置いてあります ○ http://www.slideshare.net/magoroku15/2012/3/24 6
  • 教材 Unix version6  テキスト ○ Lions Commentary on UNIX / ASCII Books 3990円  原著online版 ○ http://v6.cuzuco.com/v6.pdf ○ http://www.lemis.com/grog/Documentation/Lions/boo k.pdf PDP-11/40  PDP-11 Processor Handbook  http://pdos.csail.mit.edu/6.097/readings/pdp11-40.pdf2012/3/24 7
  • ウォームアップ OSの領域はプログラマにとっての最底辺部  アプリケーションプログラマ ○ 提供されるAPIを利用して、一般向けのサービス等を提供する人  システムプログラマ ○ ハードウェアの機能を利用して、API等プログラマ向け機能を提供 する人  必要とされる前提知識が異なる  命令レベルで計算機を(ぼんやりと)理解する必要あり アプリケーションプログラマ向けの準備運動  Lions本 ○ 第2章 Fundamentals (PDFだとP4) 命令セット ○ 第9章 Hardware Interrupt and Traps (PDFのP42) 割り込み  PDP-11 Processor Handbook2012/3/24 8
  • Lions本 2章2012/3/24 9
  • システムプログラマから見た計算機の構成要素 CPU  レジスタ ○ 汎用レジスタ 一般の演算命令に使用 ○ スタックポインタ スタックの先頭位置 ○ プログラムカウンタ 次に処理する命令の位置  フラグレジスタ 演算結果の一部を記憶  制御/状態レジスタ Memory 外部記憶2012/3/24 10
  • PDP-11/40 レジスタ  16bitのレジスタが8個  r0-r7  r6はspスタックポインタ  r7はpcプログラムカウンタ Processor Status Word  フラグレジスタ+状態レジスタ memory  仮想アドレス幅は16bit 最大 64kbyte  物理アドレス幅は18bit 最大 256kbyte2012/3/24 11
  • レジスタ r0-r7r0, r1 演算結果の一時的な保持、復帰値などr2, r3, r4 関数内のローカル変数。呼ばれた関数で退避し、 関数の終了時に復元R5 フレームポインタr6 (sp) スタックポインタr7 (pc) 実行する命令の位置(アドレス)2012/3/24 12
  • Processor Status Word (PSW) 14-15 現在のモード (00 = kernel 11 = user) 12-13 以前のモード 5-7 プロセッサの優先度 (0~7) 4 トラップビット 3N 演算結果が負 2Z 演算結果が0 1V 演算結果がオーバフロー 0C 演算結果がキャリー2012/3/24 13
  • CPUの処理 以下を繰り返す 1. PCの示す位置(アドレス)から命令を読み込む 2. 解析して 3. 実行 4. 実行の副作用として以下の事象が発生する  PSWを書き換え  PCを書き換え  レジスタの書き換え  メモリの内容を書き換えたりする2012/3/24 14
  • CPUの処理 誤解しやすい点 PCもレジスタの一種  PC(r7)を書き換えると処理がジャンプ 比較と分岐は別命令2012/3/24 15
  • UNIXカーネルを理解するための2012/3/24 16
  • C言語の空間モデル Text text  命令列の格納領域  書き換え禁止 data Data bss  非0で初期化されたデータ領域 Bss  0で初期化されたデータ領域 Stack  自動(auto)変数の格納領域  関数呼び出し時のレジスタ退避域 stack注)スレッドは、まだ存在しないので対象外2012/3/24 17
  • 変数の宣言と空間配置int i; // Bss a.out形式 実行時 (ファイル) (メモリ)Int j = 1; // Data headermain() text text{ data data static int k = 1; // Data int l = 1; // Stack bss int m; // Stack :} stack2012/3/24 18
  • 関数呼び出しとスタック Cmain(){ int e, f, r; e = 1; f = 2; r = func(e, f);}int c, d;func(a, b){ c = a; d = b; return c + d;}2012/3/24 19
  • 関数とスタック namelist# nm -n a.out 000170T cret 0x78000000a 0x00 crt0.o 000206B _c000000t start 000210B _d000004a a 000212B savr5000006a b 177764a r000030T 0x18 _main 177766a f000030a src.o 177770a e000030t ~main000102T 0x42 _func000102t ~func000140T 0x60 _exit000140a exit.o000152T 0x6a csv000152a csv.o2012/3/24 20
  • 関数呼び出しとスタック ASM.globl _main .comm _c,2.text .globl _d _main: .comm _d,2 ~~main: .globl _func ~e=177770 .text ~f=177766 _func: ~r=177764 ~~func: jsr r5,csv ~a=4 sub $6,sp ~b=6 mov $1,-10(r5) jsr r5,csv mov $2,-12(r5) mov 4(r5),_c mov -12(r5),(sp) mov 6(r5),_d mov -10(r5),-(sp) mov _c,r0 jsr pc,*$_func add _d,r0 tst (sp)+ jbr L2 mov r0,-14(r5) L2: jmp cretL1: jmp cret .globl.globl _c .data2012/3/24 21
  • csv 関数の入り口Main: csv: : mov r5,r0 jsr r5,csv mov sp,r5 : mov r4,-(sp) mov r3,-(sp) mov r2,-(sp) tst -(sp) jmp (r0) r0 r1 r2 r3 r4 r5 r6:sp r7:pc---- 0484, 0000, 0000, 0000, 0000, 0000, 047e, 0018 jsr r5,006a---- 0484, 0000, 0000, 0000, 0000, 001c, 047c, 006a mov r5,r0---- 001c, 0000, 0000, 0000, 0000, 001c, 047c, 006c mov sp,r5---- 001c, 0000, 0000, 0000, 0000, 047c, 047c, 006e mov r4,-(r6)-z-- 001c, 0000, 0000, 0000, 0000, 047c, 047a, 0070 mov r3,-(r6)-z-- 001c, 0000, 0000, 0000, 0000, 047c, 0478, 0072 mov r2,-(r6)-z-- 001c, 0000, 0000, 0000, 0000, 047c, 0476, 0074 tst -(r6)-z-- 001c, 0000, 0000, 0000, 0000, 047c, 0474, 00762012/3/24 jmp (r0) 22
  • cret 関数の出口 main: cret: : mov r5,r1 jmp cret mov -(r1),r4 : mov -(r1),r3 mov -(r1),r2 mov r5,sp mov (sp)+,r5 rts pc r0 r1 r2 r3 r4 r5 r6:sp r7:pc---- 0003, 0462, 0000, 0000, 0000, 047c, 046e, 003e jmp 0078---- 0003, 0462, 0000, 0000, 0000, 047c, 046e, 0078 mov r5,r1---- 0003, 047c, 0000, 0000, 0000, 047c, 046e, 007a mov -(r1),r4-z-- 0003, 047a, 0000, 0000, 0000, 047c, 046e, 007c mov -(r1),r3-z-- 0003, 0478, 0000, 0000, 0000, 047c, 046e, 007e mov -(r1),r2-z-- 0003, 0476, 0000, 0000, 0000, 047c, 046e, 0080 mov r5,r6---- 0003, 0476, 0000, 0000, 0000, 047c, 047c, 0082 mov (r6)+,r5-z-- 0003, 0476, 0000, 0000, 0000, 0000, 047e, 0084 rts 0084 2012/3/24 23
  • JSR – Jump to SubRoutinejsr src,dst 以下と等価 1. MOV src,-(R6) srcをスタックにpush 2. MOV PC,src 次の命令のPCをsrcに転送 3. JMP dst dstにジャンプ jsr r5,0x006aの処理は以下 1. r5の値をstackに入れて、spを-2 (push) 2. Jsrの次に実行する(戻り先)アドレスをr5に入 れて 3. PCにdstを入れてジャンプ2012/3/24 24
  • RTS – ReTurn from Subroutinerts src 以下と等価 1. MOV src,PC 2. MOV (R6)+,src jsr r7の処理は以下 1. r7の値をPCに入れて(この場合は意味なし) 2. スタックの内容+2 (pop) してr7へ pcの書き換えによりジャンプ2012/3/24 25
  • main 引数の設定とfuncの呼出し # r0 r1 r2 r3 r4 r5 r6 r715: 001c,0000,0000,0000,0000,047c,0474,001c sub $6,r6 main16: 001c,0000,0000,0000,0000,047c,046e,0020 mov $1,-8(r5) main17: 001c,0000,0000,0000,0000,047c,046e,0026 mov $2,-a(r5) main18: 001c,0000,0000,0000,0000,047c,046e,002c mov -a(r5),(r6) main19: 001c,0000,0000,0000,0000,047c,046e,0030 mov -8(r5),-(r6) main20: 001c,0000,0000,0000,0000,047c,046c,0034 jsr r7,*$0x0040 main21: 001c,0000,0000,0000,0000,047c,046a,0042 jsr r5,0x006a func #15 #16-17 #18 #19 #20 0x046a r6→ 0x0038 0x046c r6→ 1 1 0x046e r6→ r6→ r6→ 2 2 2 0x0470 0x0472 2 2 2 2 0x0474 r6→ 1 1 1 1 0x0476 0x0478 0x047a 0x047c r5→ r5→ r5→ r5→ r5→2012/3/24 26
  • funcの入り口 (func-csv) # r0 r1 r2 r3 r4 r5 r6 r7 21: 001c,0000,0000,0000,0000,047c,046a,0042 jsr r5,0x006a func 22: 001c,0000,0000,0000,0000,0046,0468,006a mov r5,r0 func-csv 23: 0046,0000,0000,0000,0000,0046,0468,006c mov r6,r5 func-csv 24: 0046,0000,0000,0000,0000,0468,0468,006e mov r4,-(r6) func-csv 25: 0046,0000,0000,0000,0000,0468,0466,0070 mov r3,-(r6) func-csv 26: 0046,0000,0000,0000,0000,0468,0464,0072 mov r2,-(r6) func-csv 27: 0046,0000,0000,0000,0000,0468,0462,0074 tst -(r6) func-csv 28: 0046,0000,0000,0000,0000,0468,0460,0076 jmp (r0) func #21 #23 #24-26 #27 0x045a 0x045c 0x045e 0x0460 r6→ 0x0462 r6→ r2 r2 0x0464 r3 r3 0x0466 r4 r4 0x0468 r6→ 0x047c r5,r6→ 0x047c r5→ 0x047c r5→ 0x047c 0x046a r6→ 0x0038 0x0038 0x0038 0x0038 0x046c2012/3/24 27
  • funcの出口 (func-cret) # r0 r1 r2 r3 r4 r5 r6 r734:0003,0000,0000,0000,0000,0468,0460,005c jmp 0x00078 func35:0003,0000,0000,0000,0000,0468,0460,0078 mov r5,r1 func-cret36:0003,0468,0000,0000,0000,0468,0460,007a mov -(r1),r4 func-cret37:0003,0466,0000,0000,0000,0468,0460,007c mov -(r1),r3 func-cret38:0003,0464,0000,0000,0000,0468,0460,007e mov -(r1),r2 func-cret39:0003,0462,0000,0000,0000,0468,0460,0080 mov r5,r6 func-cret40:0003,0462,0000,0000,0000,0468,0468,0082 mov (r6)+,r5 func-cret41:0003,0462,0000,0000,0000,047c,046a,0084 rts r7 func-cret42:0003,0462,0000,0000,0000,047c,046c,0038 tst (r6)+ main #27-34 #35 #36-38 #39 #40-41 0x045a 0x045c 0x045e 0x0460 r6→ r6→ r6→ 0x0462 r2 r2 r1→ r2 0x0464 r3 r3 r3 0x0466 r4 r4 r4 0x0468 r5→ 0x047c r5,r1→ 0x047c r5→ 0x047c r5,r6→ 0x047c r6→ 0x047c 0x046a 0x0038 0x0038 0x0038 0x0038 r6→ 0x0038 0x046c r6→2012/3/24 28
  • 関数とスタック 今のスタックr6:SP 前のスタックr5 r5:r6のペアでチェーン #20 #21 #27 0x0460 r6→ 0x0462 r2 0x0464 r3 0x0466 r4 0x0468 r6→ 0x047c r5→ 0x047c 0x046a 0x0038 0x0038 0x0038 0x046c 1 0x046e 2 0x0470 0x0472 2 0x0474 1 0x0476 0x0478 0x047a 0x047c r5→2012/3/24 29
  • レジスタ r0-r7 もう一度r0, r1 演算結果の一時的な保持、復帰値などr2, r3, r4 関数内のローカル変数。呼ばれた関数で退避し、 関数の終了時に復元R5 フレームポインタr6 (sp) スタックポインタr7 (pc) 実行する命令の位置(アドレス)2012/3/24 30
  • C言語とasmの実行環境 asmから生成した命令列はスタックを必要と しない C言語から生成した命令列は、実行時にス タックを必要とする  引数の受け渡し利用領域  自動変数の領域  呼び出し元レジスタ(r2,r3,r4)の退避領域  呼び出し先からの復帰アドレスの退避領域2012/3/24 31
  • UNIXカーネルを理解するための2012/3/24 32
  • getpid(2)の呼び出し C言語main(){ int i; i = getpid();}2012/3/24 33
  • getpid(2)の呼び出し ASM.globl _main.text _main: ~~main: ~i=177770 jsr r5,csv tst -(sp) jsr pc,_getpid mov r0,-10(r5)L1: jmp cret.globl.data2012/3/24 34
  • getpid.s /usr/source/s4/getpid.sgetpid = 20..globl _getpid_getpid: mov r5,-(sp) mov sp,r5 sys getpid mov (sp)+,r5 rts pc2012/3/24 35
  • getpid.sの実行トレース3: 001c, 0000, 0000, 0000, 0000, 0446, 043c, 001e jsr r7, 0x000344: 001c, 0000, 0000, 0000, 0000, 0446, 043a, 0034 mov r5, -(r6)5: 001c, 0000, 0000, 0000, 0000, 0446, 0438, 0036 mov r6,r56: 001c, 0000, 0000, 0000, 0000, 0438, 0438, 0038 sys getpid7: 001c, 0000, 0000, 0000, 0000, 0438, 0438, 003a mov (r6)+, r58: 001c, 0000, 0000, 0000, 0000, 0446, 043a, 003c rts r7 なんか変じゃない2012/3/24 36
  • open(2)の呼び出し C言語main(){ int f; f = open("hoge", 2);}2012/3/24 37
  • open(2)の呼び出し ASM.globl _main.text _main: ~~main: ~f=177770 jsr r5,csv tst -(sp) mov $2,(sp) mov $L2,-(sp) jsr pc,*$_open tst (sp)+ mov r0,-10(r5)L1: jmp cret.globl.dataL2:.byte 150,157,147,145,02012/3/24 38
  • open.s /usr/source/s5/open.sglobl _open, cerror_open: mov r5,-(sp) mov sp,r5 mov 4(r5),0f mov 6(r5),0f+2 sys 0; 9f bec 1f jmp cerror1: mov (sp)+,r5 rts pc.data9: sys open;0: ..; ..2012/3/24 39
  • open.sの実行トレース# r0 r1 r2 r3 r4 r5 r6 r71: 001c, 0000, 0000, 0000, 0000, 0482, 0474, 0034 mov r5,-(r6)2: 001c, 0000, 0000, 0000, 0000, 0482, 0472, 0036 mov r6,r53: 001c, 0000, 0000, 0000, 0000, 0472, 0472 0038 mov 4(r5), 0x008e4: 001c, 0000, 0000, 0000, 0000, 0472, 0472, 003e mov 6(r5), 0x00905: 001c, 0000, 0000, 0000, 0000, 0472, 0472, 0044 sys indir 0x0008c6: 0003, 0000, 0000, 0000, 0000, 0472, 0472, 0048 bcc 0x0004e7: 0003, 0000, 0000, 0000, 0000, 0472, 0472, 004e mov (r6)+, r58: 0003, 0000, 0000, 0000, 0000, 0482, 0474, 0050 rts なんか変じゃない2012/3/24 40
  • システムコールとライブラリコール ライブラリ  マニュアルセクション3  例 fopen(3)  ユーザプログラムの空間で動作  必要に応じてシステムコールを呼び出す システムコール  マニュアルセクション2  例 open(2)  OS内部の処理を呼び出す  呼出し方法は通常のCall/Returnとは異なる2012/3/24 41
  • OSを実装するための2012/3/24 42
  • Q:CPUが想定外の状態になると たとえば以下の場合  不正なアドレスを参照した  未定義の命令を実行しようとした  0で割り算した 次の命令はどこから取り出せばよいか?2012/3/24 43
  • A: わな “Trap”を用意しておく CPUが身動きが取れなかった場合に次に命令 を取り出す場所を“わな”として仕掛けてお く システムコールの呼び出しは特殊な「わな」 「わな」はCPUの処理過程に実行時の例外と して発生する 「わな」に引っかかる事を「例外」と呼ぶ2012/3/24 44
  • 例外と割り込み Lions本9章 Trap/例外  命令の実行に失敗した場合の「わな」仕掛ける  システムコールの呼び出しは特殊な「わな」  「わな」はCPUの処理過程で発生する Interrupt/割り込み  CPUの処理に関係なく、外部からの「割り込み」  主に、外部装置の処理完了時に「割り込む」  外部装置の例 ○ テレタイプ、紙テープ、ラインプリンタ、磁気ディ スク、時計2012/3/24 45
  • 2012/3/24 46
  • 例外の流れ1. 例外/割り込みの発生2. コンテキストの保存 ① PCとPSWをCPU内部に一時的に保存 ② 発生の要因を特定し、要因:アドレスの表(ベクター)を 検索 ③ ベクターをPCに設定 ④ 一時的に保存していたPC,PSWをカーネルスタックに 退避(push)3. ハンドラの実行4. コンテキストの復元 ① カーネルスタックにPC,PSWが格納されている状態で rtt命令を実行 ② rtt命令がカーネルスタックからPC,PSWを復元(pop)5. 割り込み発生の次の命令を実行2012/3/24 47
  • 例外ベクタ Vector Trap type Priority Location 004 Bus timeout 7 010 Illegal instruction 7 014 bpt-trace 7 020 iot 7 024 Power failure 7 030 Emulator trap 7 034 Trap instruction/ system entry 7 114 11/70 parity 7 240 Programmed interrupt 7 244 Floating point error 7 250 Segmentation violation 72012/3/24 48
  • 5000500 / low core05010505 br7 = 34005060507 . = 0^.0508 br 1f0509 405100511 / trap vectors0512 trap; br7+0. / bus error0513 trap; br7+1. / illegal instruction0514 trap; br7+2. / bpt-trace trap0515 trap; br7+3. / iot trap0516 trap; br7+4. / power fail0517 trap; br7+5. / emulator trap0518 trap; br7+6. / system entry2012/3/24 49
  • 7520752 .globl trap, call0753 /* -------------- */0754 .globl _trap0755 trap:0756 mov PS,-4(sp)0757 tst nofault0758 bne 1f0759 mov SSR0,ssr0760 mov SSR2,ssr+40761 mov $1,SSR00762 jsr r0,call1; _trap0763 / no return2012/3/24 50
  • 26932693 trap(dev, sp, r1, nps, r0, pc, ps)2694 {2695 register i, a;2696 register struct sysent *callp;26972698 savfp();2699 if ((ps&UMODE) == UMODE)2700 dev =| USER; 27502702 switch(dev) { :2715 default:2716 printf("ka6 = %o¥n", *ka6);2717 printf("aps = %o¥n", &ps);2718 printf("trap type %o¥n", dev);2719 panic("trap");2721 case 0+USER: /* bus error *2722 i = SIGBUS;2723 break;2012/3/24 51
  • 27512751 case 6+USER: /* sys call */2752 u.u_error = 0;2753 ps =& ~EBIT;2754 callp = &sysent[fuiword(pc-2)&077]; PCは”わな”に落ちた命令の次のアドレス この命令は2バイトなので2を引いて ユーザ空間からword(2バイト)を読み 下位6ビットを取り出す この値をindexにしてsysentを見ると2012/3/24 52
  • 29062906 * to the appropriate routine for processing a system call.2907 * Each row contains the number of arguments2908 * and a pointer to the routine.2909 */2910 int sysent[]2911 {2912 0, &nullsys, /* 0 = indir */2913 0, &rexit, /* 1 = exit */2914 0, &fork, /* 2 = fork */2915 2, &read, /* 3 = read */2916 2, &write, /* 4 = write */2917 2, &open, /* 5 = open */2012/3/24 53
  • システムコール番号indir = 0.exit = 1.fork = 2.read = 3.write = 4.open = 5.close = 6.wait = 7.creat = 8. : :2012/3/24 54
  • システムコール呼出し処理1. C言語で open(“aa”, 2)2. Libcで sys 5 を実行  sysはemulator trap instruction3. ユーザプログラム空間から5を取り出して4. sysent[5]でカーネル内のopen処理を見つけ5. カーネル内部のopen処理を呼ぶ2012/3/24 55
  • 2012/3/24 56
  • 割り込みベクタ Vector device priority Location 060 Teletype input 4 064 Teletype output 4 070 Paper tape input 4 074 Paper tape output 4 100 Line clock 6 104 Programmable clock 6 200 Line printer 4 220 RK disk driver 52012/3/24 57
  • Teletype ?2012/3/24 58
  • Paper tape ?2012/3/24 59
  • Clocks – line and programmable Line Clock  電源の周期から生成  AC>降圧(トランス)>整流(ダイオード)>コンデンサ  電源周波数のパルスを取り出せる  50HZで20ms間隔  昔の電気式デジタル時計はパルスxHZで1秒を生成 Programmable clock  指定の間隔でパルスを発生 PDP-11ではどちらかが必要2012/3/24 60
  • 525 low.s0525: . = 60^. Vector device entry0526: klin; br40527: klou; br4 060 Teletype input klin0528:0529: . = 70^. 064 Teletype output klou0530: pcin; br40531: pcou; br4 070 Paper tape input pcin0532: 074 Paper tape output pcou0533: . = 100^.0534: kwlp; br6 100 Line clock kwlp0535: kwlp; br60539: 104 Programmable clock kwlp0540: . = 200^.0541: lpou; br4 200 Line printer lpou0542:0543: . = 220^. 220 RK disk driver rkio0544: rkio; br52012/3/24 61
  • Line Clock 外部にあるclockから毎秒50個のパルスがCPUに 入る 1パルス毎に割り込みベクタの処理を実行 Clock CPU2012/3/24 62
  • kwlp low.s0568:0569: .globl _clock0570: kwlp: jsr r0,call; _clockCで書かれたclock()を呼ぶ2012/3/24 63
  • clock3725: clock(dev, sp, r1, nps, r0, pc, ps) 3761: 3797: if(++lbolt >= HZ) {3726: { 3762: /* 3798: if((ps&0340) != 0)3727: register struct callo *p1, *p2; 3763: * callout 3799: return;3728: register struct proc *pp; 3764: */ 3800: lbolt =- HZ;3729: 3765: 3801: if(++time[1] == 0)3730: /* 3766: spl5(); 3802: ++time[0];3731: * restart clock 3767: if(callout[0].c_time <= 0) { 3803: spl1();3732: */ 3768: p1 = &callout[0]; 3804: if(time[1]==tout[1] && time[0]==tout[0])3733: 3769: while(p1->c_func != 0 && p1->c_time <= 0) { 3805: wakeup(tout);3734: *lks = 0115; 3770: (*p1->c_func)(p1->c_arg); 3806: if((time[1]&03) == 0) {3735: 3771: p1++; 3807: runrun++;3736: /* 3772: } 3808: wakeup(&lbolt);3737: * display register 3773: p2 = &callout[0]; 3809: }3738: */ 3774: while(p2->c_func = p1->c_func) { 3810: for(pp = &proc[0]; pp < &proc[NPROC]; pp++)3739: 3775: p2->c_time = p1->c_time; 3811: if (pp->p_stat) {3740: display(); 3776: p2->c_arg = p1->c_arg; 3812: if(pp->p_time != 127)3741: 3777: p1++; 3813: pp->p_time++;3742: /* 3778: p2++; 3814: if((pp->p_cpu & 0377) > SCHMAG)3743: * callouts 3779: } 3815: pp->p_cpu =- SCHMAG; else3744: * if none, just return 3780: } 3816: pp->p_cpu = 0;3745: * else update first non-zero time 3781: 3817: if(pp->p_pri > PUSER)3746: */ 3782: /* 3818: setpri(pp);3747: 3783: * lightning bolt time-out 3819: }3748: if(callout[0].c_func == 0) 3784: * and time of day 3820: if(runin!=0) {3749: goto out; 3785: */ 3821: runin = 0;3750: p2 = &callout[0]; 3786: 3822: wakeup(&runin);3751: while(p2->c_time<=0 && p2->c_func!=0) 3787: out: 3823: }3752: p2++; 3788: if((ps&UMODE) == UMODE) { 3824: if((ps&UMODE) == UMODE) {3753: p2->c_time--; 3789: u.u_utime++; 3825: u.u_ar0 = &r0;3754: 3790: if(u.u_prof[3]) 3826: if(issig())3755: /* 3791: incupc(pc, u.u_prof); 3827: psig();3756: * if ps is high, just return 3792: } else 3828: setpri(u.u_procp);3757: */ 3793: u.u_stime++; 3829: }3758: 3794: pp = u.u_procp; 3830: }3759: if((ps&0340) != 0) 3795: if(++pp->p_cpu == 0) 3831: }3760: goto out; 3796: pp->p_cpu--; 2012/3/24 64
  • clock3725: clock(dev, sp, r1, nps, r0, pc, ps) 3761: 3797: if(++lbolt >= HZ) {3726: { 3762: /* 3798: if((ps&0340) != 0)3727: register struct callo *p1, *p2; 3763: * callout 3799: return;3728: register struct proc *pp; 3764: */ 3800: lbolt =- HZ;3729: 3765: 3801: if(++time[1] == 0)3730: /* 3766: spl5(); 3802: ++time[0];3731: * restart clock 3767: if(callout[0].c_time <= 0) { 3803: spl1();3732: */ 3768: p1 = &callout[0]; 3804: if(time[1]==tout[1] && time[0]==tout[0])3733: 3769: while(p1->c_func != 0 && p1->c_time <= 0) { 3805: wakeup(tout);3734: *lks = 0115; 3770: (*p1->c_func)(p1->c_arg); 3806: if((time[1]&03) == 0) {3735: 3771: p1++; 3807: runrun++; Callout3736: /* 3772: } 3808: wakeup(&lbolt);3737: * display register 3773: p2 = &callout[0]; 3809: }3738: */ 3774: while(p2->c_func = p1->c_func) { 3810: for(pp = &proc[0]; pp < &proc[NPROC]; pp++)3739: 3775: p2->c_time = p1->c_time; 3811: if (pp->p_stat) { Sched3740: display(); 3776: p2->c_arg = p1->c_arg; 3812: if(pp->p_time != 127)3741: 3777: p1++; 3813: pp->p_time++;3742: /* 3778: p2++; 3814: if((pp->p_cpu & 0377) > SCHMAG)3743: * callouts 3779: } 3815: pp->p_cpu =- SCHMAG; else3744: * if none, just return 3780: } 3816: pp->p_cpu = 0;3745: * else update first non-zero time 3781: 3817: if(pp->p_pri > PUSER) の入り口3746: */ 3782: /* 3818: setpri(pp);3747: 3783: * lightning bolt time-out 3819: }3748: if(callout[0].c_func == 0) 3784: * and time of day 3820: if(runin!=0) {3749: goto out; 3785: */ 3821: runin = 0;3750: p2 = &callout[0]; 3786: 3822: wakeup(&runin); Acct3751: while(p2->c_time<=0 && p2->c_func!=0) 3787: out: 3823: }3752: p2++; 3788: if((ps&UMODE) == UMODE) { 3824: if((ps&UMODE) == UMODE) {3753: p2->c_time--; 3789: u.u_utime++; 3825: u.u_ar0 = &r0;3754: 3790: if(u.u_prof[3]) 3826: if(issig())3755: /* 3791: incupc(pc, u.u_prof); 3827: psig();3756: * if ps is high, just return 3792: } else 3828: setpri(u.u_procp);3757: */ 3793: u.u_stime++; 3829: }3758: 3794: pp = u.u_procp; 3830: }3759: if((ps&0340) != 0) 3795: if(++pp->p_cpu == 0) 3831: }3760: goto out; 3796: pp->p_cpu--; 2012/3/24 65
  • 謎の変数 u.u_time u.u_stime pp->p_time lbolt time[2] tout[2]2012/3/24 66
  • callout 構造struct callo{ int c_time; /* ticks between events */ int c_arg; /* function argument */ int (*c_func)(); /* function pointer */} callout[NCALL];2012/3/24 67
  • clock callout (1/2) 先頭のcalloutが未3748: if(callout[0].c_func == 0) 登録なら、後続の3749: goto out;3750: p2 = &callout[0]; calloutも未登録と 判断して,Callout 処理をスキップ3751: while(p2->c_time<=0 && p2->c_func!=0)3752: p2++; 最初にc_timeが03753: p2->c_time--; より大きいCallout3758: を見つけて、3759: if((ps&0340) != 0) c_timeを-13760: goto out; ここより前の3761: calloutはこの後処 理される2012/3/24 68
  • clock callout (2/2) 先頭に登録時間が 過ぎているcallout3766: spl5(); が存在したら、3767: if(callout[0].c_time <= 0) {3768: p1 = &callout[0];3769: while(p1->c_func != 0 && p1->c_time <= 0) {3770: (*p1->c_func)(p1->c_arg);3771: p1++; 処理を実行3772: }3773: p2 = &callout[0];3774: while(p2->c_func = p1->c_func) {3775: p2->c_time = p1->c_time; Callout配列を詰め3776: p2->c_arg = p1->c_arg; る3777: p1++;3778: p2++;3779: }3780: }2012/3/24 69
  • clock acct USERモードから3787: out: 割り込まれたら、3788: if((ps&UMODE) == UMODE) { uのuser時間3789: u.u_utime++; u_utimeを+13790: if(u.u_prof[3])3791: incupc(pc, u.u_prof); KERNELモードか3792: } else ら割り込まれたら、3793: u.u_stime++; uのsystem時間 u_stimeを+13794: pp = u.u_procp;3795: if(++pp->p_cpu == 0) Procのp_cpuを加3796: pp->p_cpu--; 算。オーバフロー しないように調整ppはproc構造のポインタ、uはuser構造。共にプロセスの管理構造1プロセスに1個づつ2012/3/24 70
  • clock schedの入り口(1/2) clockが呼ばれると、ここまでは必3797: if(++lbolt >= HZ) { ず実行。lboltを+1して、HZ(50)を3798: if((ps&0340) != 0)3799: return; 超過したら、すなわち1秒経過し3800: lbolt =- HZ; たら、3801: if(++time[1] == 0)3802: ++time[0]; lboltをリセット3803: spl1();3804: if(time[1]==tout[1] && time[0]==tout[0])3805: wakeup(tout); 寝ているプロセスを起こす3806: if((time[1]&03) == 0) {3807: runrun++;3808: wakeup(&lbolt);3809: } 4秒ごとにlboltで待ってるプロセ スを起こす 今回はさらりと流す2012/3/24 71
  • clock schedの入り口(2/2) 3810: for(pp = &proc[0]; pp < &proc[NPROC]; pp++) プロセスの管理構造の配 3811: if (pp->p_stat) { 列をスキャン 3812: if(pp->p_time != 127) 3813: pp->p_time++; 3814: if((pp->p_cpu & 0377) > SCHMAG) p_statに値が入っている=プロ 3815: pp->p_cpu =- SCHMAG; elseセスが存在したら、p_timeを 3816: pp->p_cpu = 0; +1 3817: if(pp->p_pri > PUSER) 3818: setpri(pp); 3819: } 3820: if(runin!=0) { 3821: runin = 0; 3822: wakeup(&runin); runinが真なら、runinで待って 3823: } るプロセスをwakeup 3824: if((ps&UMODE) == UMODE) { 3825: u.u_ar0 = &r0; 3826: if(issig()) 3827: psig(); 3828: setpri(u.u_procp); 3829: } 3830:2012/3/24 } 72
  • 謎の変数 回答 u.u_time USER時間 u.u_stime SYSTEM時間 pp->p_time プロセス起動からの時間 lbolt 毎秒60回++ time[2] 1970年からの秒 tout[2] sleep(2)が起きる時間2012/3/24 73
  • Unix のPPDA (PerProcDataArea) User構造体 user.h The user structure. One allocated per process. Contains all per process data that doesnt need to be referenced while the process is swapped. Proc構造体 proc.h One structure allocated per active process. It contains all data needed about the process while the process may be swapped out. Other per process data (user.h) is swapped with the process.2012/3/24 74
  • 2012/3/24 75
  • a.outと空間の関係 CPU PC a.out header text text data data exec(2) bss ・関数を呼 び出すと自3076 /* read in first 8 bytes 動的に割り3077 * of file for segment 当てる。3078 * sizes: ・呼び出し3079 * w0 = 407/410/4113080 * w1 = text size からの復帰3081 * w2 = data size に備えてレ3082 * w3 = bss size stack ジスタの内3083 */ 容を退避。 2012/3/24 76
  • 例外/割り込みが起こると…….. •PSWのモードがユーザモー CPU PC ドからカーネルモードに変わ り、空間が切り替わる。 ① ② •事象に応じて、ベクター テーブルの値がPCに書き込 text ③ text A まれる。 data data •例外/割り込み発生時のPSW とPC(図中A)をスタックに pushする bss bssアプリケーション カーネル アプリケーションと stack stack カーネル 2つの空間?? 2012/3/24 77
  • 仮想アドレスと物理アドレス 現在の一般的な仮想記憶  仮想アドレス>物理アドレス  仮想メモリ量>物理メモリ量  実メモリ不足時は固定長(ページ)単位で2次記憶に退避 し必要時に復元 →ページング PDP-11の仮想記憶  仮想アドレス<物理アドレス  仮想メモリ量<物理メモリ量  実メモリ不足時はプロセス全体を2次記憶に退避し実行 を抑止、一定時間経過後に全体を復元し実行可能に →スワッピング2012/3/24 78
  • 仮想記憶のための仕組み ハードウェアのサポートが必要 仮想アドレス→物理アドレスの変換機構 CPU memory 変換機構なし CPU 変換表 memory 変換機構あり2012/3/24 79
  • アドレス変換機構の制御 リセット後は変換機構OFFで動作 OSの初期化時にプログラムで 1. 変換表を初期化 2. 変換機構をON  新しいプロセスの生成とメモリ獲得時に  OSが変換表を編集  プロセスの切り替え時に  変換表を入れ替え2012/3/24 80
  • PDP-11/40のメモリ管理機構 8個のカーネルモードページ 8個のユーザモードページ 1ページは最大8Kbyteの可変長 モード切り替えはPSWのモードに連動2012/3/24 81
  • Active Page Registers (APR)2012/3/24 82
  • APR- PARとPDRのペア PAR ベースアドレスを指定 PDR メモリ属性を指定2012/3/24 83
  • 仮想記憶の有効化 bit0 ENABLE MANAGEMENTを1で有効2012/3/24 84
  • 重要なアドレス m40.s USIZE = 16 Size of User Block (*64 = 1024 B) PS = 177776 Program Status Word SSR0 = 177572 Status Register KISA0 = 172340 Kernel Segment Address Register #0 KISA6 = 172354 Kernel Segment Address Register #6 KISD0 = 172300 Kernel Segment Descriptor Register #0 UISA0 = 177640 User Segment Address Register #0 UISA1 = 177642 User Segment Address Register #1 UISD0 = 177600 User Segment Descriptor Register #0 UISD1 = 177602 User Segment Descriptor Register #1 IO = 7600 I/O Segment Register2012/3/24 85
  • start 仮想空間の設定0612: start:0613: bit $1,SSR00614: bne start / loop if restart0615: reset0616:0617: / initialize systems segments0618:0619: mov $KISA0,r00620: mov $KISD0,r10621: mov $200,r40622: clr r20623: mov $6,r30624: 1:0625: mov r2,(r0)+0626: mov $77406,(r1)+ / 4k rw0627: add r4,r20628: sob r3,1b2012/3/24 86
  • ユーザ空間の初期化 start0630: / initialize user segment0631:0632: mov $_end+63.,r20633: ash $-6,r20634: bic $!1777,r20635: mov r2,(r0)+ / ksr6 = sysu0636: mov $usize-1¥<8|6,(r1)+0637:0638: / initialize io segment0639: / set up counts on supervisor segments0640:0641: mov $IO,(r0)+0642: mov $77406,(r1)+ / rw 4k0643:0644: / get a sp and start segmentation0645:0646: mov $_u+[usize*64.],sp0647: inc SSR02012/3/24 87
  • bssとuのクリア0646: mov $_u+[usize*64.],sp0647: inc SSR00648:0649: / clear bss0650:0651: mov $_edata,r00652: 1:0653: clr (r0)+0654: cmp r0,$_end0655: blo 1b0656:0657: / clear user block0658:0659: mov $_u,r00660: 1:0661: clr (r0)+0662: cmp r0,$_u+[usize*64.]0663: blo 1b2012/3/24 88
  • mainの呼び出し0665: / set up previous mode and call main0666: / on return, enter user mode at 0R0667:0668: mov $30000,PS0669: jsr pc,_main0670: mov $170000,-(sp)0671: clr -(sp)0672: rtt2012/3/24 89
  • 最初のプロセスを生成1627: if(newproc()) {1628: expand(USIZE+1);1629: estabur(0, 1, 0, 0);1630: copyout(icode, 0, sizeof icode);1631: /*1632: * Return goes to loc. 0 of user init1633: * code just copied out.1634: */1635: return;1636: }1637: sched();2012/3/24 90
  • icode1511: /*1512: * Icode is the octal bootstrap1513: * program executed in user mode1514: * to bring up the system.1515: */1516: int icode[]1517: {1518: 0104413, /* sys exec; init; initp */1519: 0000014,1520: 0000010, char* init = “/etc/init”;1521: 0000777, /* br . */1522: 0000014, /* initp: init; 0 */ main( ) {1523: 0000000, execl( init, init, 0 );1524: 0062457, /* init: </etc/init¥0> */ while( 1 ) ;1525: 0061564,1526: 0064457, }1527: 0064556,1528: 0000164,1529: };2012/3/24 91
  • Bootと空間の初期化Boot直後 仮想記憶有効 最初のnewproc 最初のexec Initの実行 text text text text text data data data data data bss bss bss bss u user user user user user user IOレジスタ IOレジスタ IOレジスタ IOレジスタ icode exec text data bss stack 2012/3/24 92
  • Unixの空間モデル アプリとカーネルのアドレス域は分離  後に完全な仮想記憶サポートで少し変わる  各アプリケーションの空間は独立 カーネルの空間は  Text,Data,Bssは一部を除いて共有  Stackはアプリ毎に個別  Stackはstruct userのページの後半2012/3/24 93
  • UNIXカーネルの構造2012/3/24 94
  • PPDA - Per Processor Data Area OSを読み解く場合に最初に注目する構造 プロセスなどの実行単位毎に割り当てる領域 UNIXの場合はuserとproc2012/3/24 95
  • struct user0413 struct user0414 {0415 int u_rsav[2]; /* save r5,r6 when exchanging stacks */0416 int u_fsav[25]; /* save fp registers */0417 /* rsav and fsav must be first in structure */0418 char u_segflg; /* flag for IO; user or kernel space */0419 char u_error; /* return error code */0420 char u_uid; /* effective user id */0421 char u_gid; /* effective group id */0422 char u_ruid; /* real user id */0423 char u_rgid; /* real group id */0424 int u_procp; /* pointer to proc structure */0436 int u_uisa[16]; /* prototype of segmentation addresses */043 int u_uisd[16]; /* prototype of segmentation descriptors */2012/3/24 96
  • struct proc0358 struct proc0359 {0360 char p_stat;0361 char p_flag;0362 char p_pri; /* priority, negative is high */0363 char p_sig; /* signal number sent to this process */0364 char p_uid; /* user id, used to direct tty signals */0365 char p_time; /* resident time for scheduling */0366 char p_cpu; /* cpu usage for scheduling */0367 char p_nice; /* nice for scheduling */0368 int p_ttyp; /* controlling tty */0369 int p_pid; /* unique process id */0370 int p_ppid; /* process id of parent */0371 int p_addr; /* address of swappable image */0372 int p_size; /* size of swappable image (*64 bytes) */0373 int p_wchan; /* event process is awaiting */0374 int *p_textp; /* pointer to text structure */0376 } proc[NPROC];2012/3/24 97
  • 空間の切り替え機構 CPU PCアプリケーション カーネル PSW 00: カーネルモード text 11: ユーザモード text data 11用 00用 data APR0 APR0 APR1 APR1 bss APR2 APR2 bss APR3 APR3 APR4 APR4 APR5 APR5 APR6 APR6 struct user stack APR7 APR7 stack I/Oレジスタ 2012/3/24 98
  • アプリケーションの動作時 PSW PC •PSWのモードはユーザ •PCはアプリのtextセグメントを指す text data bss user user user user kstack kstack kstack kstack IOレジスタ 1 text text text text data data data data bss bss bss bss stack stack stack stack2012/3/24 99
  • 割り込みの発生-空間の切り替え PSW PC •PSWのモードがカーネルに •アドレス空間の制御レジスタ text がカーネルモードに切り替わる data bss user user user user kstack kstack kstack kstack IOレジスタ 1 text text text text data data data data bss bss bss bss stack stack stack stack2012/3/24 100
  • 割り込みの発生-割り込みベクタ PSW PC •割り込みベクタのエントリを text 選択してPCに data bss user user user user kstack kstack kstack kstack IOレジスタ 1 text text text text data data data data bss bss bss bss•1のアドレスとpswをスタックに退避 stack stack stack stack2012/3/24 101
  • 割り込みの発生-割り込みベクタ PSW PC •割り込みベクタのエントリを text 選択してPCに data bss Vector device 004 Bus Timeout user user Illegal instruction 010 user user kstack kstackBpt-trace kstack 014 kstack 024 iot Vector device entry IOレジスタ 034 Power failur 060 Teletype input klin 114 Emulator tarp 064 Teletype output klou instruction 1 text text text 070 text Paper tape input pcin 240 11/10 parity data data data 074 data Paper tape output pcou 244 Floting point error bss bss bss 100 bss Line clock kwlp 250 Segmentation violation 104 Programmable clock kwlp stack stack stack200 stack Line printer lpou 220 RK disk driver rkio2012/3/24 102
  • 割り込みの発生ーハンドラの処理 PSW PC 2 text data bss user user user user kstack kstack kstack kstack IOレジスタ text text text text data data data data bss bss bss bss stack stack stack stack2012/3/24 103
  • 割り込みのからの復帰 PSW PCカーネル用 APR0 text APR1 data APR2 APR3 bss APR4 APR5 APR6 user user user user APR7 kstack kstack kstack kstack IOレジスタアプリ用 •処理が終わったら、スタックのPCと 1 text text PSW復元して割り込み時点に復帰 text text APR0 APR1 data data data data APR2 APR3 bss bss bss bss APR4 APR5 APR6 stack stack stack stack APR7 2012/3/24 104
  •  以上の説明は、割り込み発生時から、復帰ま でにプロセスの切り替えが発生しない場合 条件によっては以下の処理でプロセスの切り 替えが発生 1. procの検索と選択 2. user構造の切り替え 3. User構造+kstackに退避した状態の復元 4. アプリへの復帰2012/3/24 105
  • プロセスの切り替えー選択 PSW PC Procの検索(スケジューラ) text data ↑次に動かすアプリ(プロセス) bss のprocを見つける user user user user kstack kstack kstack kstack IOレジスタ text text text text data data data data bss bss bss bss stack stack stack stack2012/3/24 106
  • プロセスの切り替えーuserの切り替え PSW PC text data proc bss user user user user kstack kstack kstack kstack IOレジスタ text text text text data data data data bss bss bss bss stack stack stack stack2012/3/24 107
  • プロセスの切り替えーuserの切り替え PSW PC text data proc bss user user user user kstack kstack kstack kstack IOレジスタアプリ用 空間管理用のレジスタを更新 APR0 text text text text APR1 data data data data APR2 APR3 bss bss bss bss APR4 APR5 APR6 stack stack stack stack APR7 2012/3/24 108
  • プロセスの切り替えーモードの切り替え •PSWをユーザに切り替え PSW PC •PCを復元 •退避していた、PCとレジスタを復元 text data proc bss user user user user kstack kstack kstack kstack IOレジスタアプリ用 APR0 text text text text APR1 data data data data APR2 APR3 bss bss bss bss APR4 APR5 APR6 stack stack stack stack APR7 2012/3/24 109
  • プロセスの切り替えー完了 PSW PC text data proc bss user user user user kstack kstack kstack kstack IOレジスタアプリ用 APR0 text text text text APR1 data data data data APR2 APR3 bss bss bss bss APR4 APR5 APR6 stack stack stack stack APR7 2012/3/24 110
  • swtch 1/32178: swtch()2179: {2180: static struct proc *p;2181: register i, n;2182: register struct proc *rp;2183:2184: if(p == NULL)2185: p = &proc[0];2186: /*2187: * Remember stack of caller2188: */2189: savu(u.u_rsav); /* save r5,r6 when exchanging stacks */2190: /*2191: * Switch to schedulers stack2192: */2193: retu(proc[0].p_addr); /* address of swappable image */2012/3/24 111
  • swtch 2/32195: loop:2196: runrun = 0;2197: rp = p;2198: p = NULL;2199: n = 128;2203: i = NPROC;2204: do {2205: rp++;2206: if(rp >= &proc[NPROC])2207: rp = &proc[0];2208: if(rp->p_stat==SRUN && (rp->p_flag&SLOAD)!=0) {2209: if(rp->p_pri < n) {2210: p = rp;2211: n = rp->p_pri;2212: }2213: }2214: } while(--i);2012/3/24 112
  • swtch 3/32223: rp = p;2224: curpri = n;2225: /* Switch to stack of the new process and set up2226: * his segmentation registers.2227: */2228: retu(rp->p_addr); /* address of swappable image */2229: sureg();2247: return(1);2012/3/24 113
  • あやしい関数2189: savu(u.u_rsav); 今のプロセスのr5,r6をuに退避2193: retu(proc[0].p_addr); uをproc0に2228: retu(rp->p_addr); uを切り替えるプロセスに2229: sureg(); uに退避してあるAPRをハードのARPに設定2012/3/24 114
  • savu 0725: _savu: 0726: bis $340,PS 0727: mov (sp)+,r1 0728: mov (sp),r0 0729: mov sp,(r0)+ 0730: mov r5,(r0)+ bis $340,PSでbit5-7を1に bic $340,PSでbit5-7を0に 0731: bic $340,PS 0732: jmp (r1) 725: 727-728: 729-730: 732: r0 u.u_rsav r1 戻り先r6→ 戻り先 戻り先 u. u.u_rsav r6→ u.u_rsav sp r5 r1 戻り先2012/3/24 115
  • retu 0740: _retu: 0745: 1: 0741: bis $340,PS 0746: mov (r0)+,sp 0742: mov (sp)+,r1 0747: mov (r0)+,r5 0743: mov (sp),KISA6 0748: bic $340,PS 0744: mov $_u,r0 0749: jmp (r1) 0413 struct user 0414 { 0415 int u_rsav[2]/* save r5,r6 when exchanging stacks */ 742: 743-744: 746-747: u. spr6→ 戻り先 戻り先 r5r6→ p_addr r6→ p_addr カーネル用 r6→ p_addr APR0 APR1 APR2 APR3 APR4 戻り先 r1 戻り先 APR5 p_addr r1 戻り先 r6 sp r0 u.u_rsav APR7 r0 u.u_rsav r5 r52012/3/24 116
  • sureg1739: sureg() 1747: up =- 8;1740: { 1748: rp =- 8;1741: register *up, *rp, a; 1749: }1742: 1750: while(rp > &UISA->r[0])1743: a = u.u_procp->p_addr; 1751: *--rp = *--up + a;1744: up = &u.u_uisa[16]; 1754: up = &u.u_uisd[16];1745: rp = &UISA->r[16]; 1755: rp = &UISD->r[16];1746: if(cputype == 40) { 1765: } アプリ用 APR0 u.u_uisa[0-7] APR1 APR2 APR3 u.u_uisd[0-7] APR4 アプリの空間を設定 APR5 APR6 APR72012/3/24 117
  • 2012/3/24 118
  • 勉強会の記録 日本Androidの会 沖縄支部 workshop@Naha Vol.17  http://atnd.org/events/25533  http://togetter.com/li/278270 横浜Androidプラットフォーム第19回勉強会  http://atnd.org/events/26444  http://togetter.com/li/2818562012/3/24 119
  • 付録2 よくわかんない人のための2012/3/24 120
  • Simhのインストールと起動 Ubuntuの場合 $ sudo apt-get install simh pdp-11のシュミレーション $ pdp11 PDP-11 simulator V3.8-1 sim>2012/3/24 121
  • Unix v6のダウンロード simh用Diskイメージのアーカイブ  http://simh.trailing-edge.com/software.html V6のイメージは以下  http://simh.trailing-edge.com/kits/uv6swre.zip ダウンロード $ wget http://simh.trailing-edge.com/kits/uv6swre.zip2012/3/24 122
  • Diskイメージの展開$ unzip uv6swre.zipArchive: uv6swre.zip inflating: README.txt inflating: unix3_v6_rk.dsk inflating: unix1_v6_rk.dsk inflating: unix2_v6_rk.dsk inflating: unix0_v6_rk.dsk inflating: AncientUnix.pdf$2012/3/24 123
  • 設定ファイルの作成 uv6swre.zipを展開したディレクトリで以下の ファイルunixv6.cfを作成 $cat unixv6.cfg set cpu 11/40 set cpu u18 att rk0 unix0_v6_rk.dsk att rk1 unix1_v6_rk.dsk att rk2 unix2_v6_rk.dsk att rk3 unix3_v6_rk.dsk boot rk0 $2012/3/24 124
  • Simhの起動$ pdp11 unixv6.cfgPDP-11 simulator V3.8-1Disabling XQ@unixLogin: root#2012/3/24 125
  • Simhのdebug機能 simhモードへの移行と復帰 # Ctrl+E Simulation stopped, PC: 021630 (MOV (SP)+,177776) sim> c #  simhモードへはCtrl+Eで  シミュレーションモードへはcで2012/3/24 126
  • ディバック機能を使う カーネルのシンボルアドレスを調べる# chdir /# nm unix | grep savu021636T _savu# savu()のアドレスは021636, breakpointを指定する# Ctrl+ESimulation stopped, PC: 021630 (MOV (SP)+,177776)sim> break 021636sim> cBreakpoint, PC: 021636 (SPL 6) savu()で止まったsim>2012/3/24 127
  • step実行Breakpoint, PC: 021636 (SPL 6)sim> e r5,sp,pcR5: 141742SP: 141730PC: 021636sim> s 0725: _savu:Step expired, PC: 021640 (MOV (SP)+,R1)sim> s 0726: bis $340,PSStep expired, PC: 021642 (MOV (SP),R0)sim> s 0727: mov (sp)+,r1Step expired, PC: 021644 (MOV SP,(R0)+)sim> s 0728: mov (sp),r0Step expired, PC: 021646 (MOV R5,(R0)+) 0729: mov sp,(r0)+sim> s 0730: mov r5,(r0)+Step expired, PC: 021650 (SPL 0)sim> s 0731: bic $340,PSStep expired, PC: 021652 (JMP (R1)) 0732: jmp (r1)2012/3/24 128
  • レジスタの調べ方/usr/share/doc/simh/simh_doc.pdfで説明e {xamine} <list> examine memory or registerssim> e state // レジスタ等すべてを表示PC: 021630 V: 0 KIPDR4: 077406 SIPDR4: 000000 UIPDR4: 000000R0: 140004 C: 0 KIPAR5: 001416 SIPAR5: 000000 UIPAR5: 000000R1: 034272 PIRQ: 000000 KIPDR5: 077406 SIPDR5: 000000 UIPDR5: 000000R2: 005336 STKLIM: 000000 KIPAR6: 001616 SIPAR6: 000000 UIPAR6: 000000R3: 000200 FAC0H: 00000000000 KIPDR6: 077406 SIPDR6: 000000 UIPDR6: 000000R4: 000000 FAC0L: 00000000000 KIPAR7: 007600 SIPAR7: 000000 UIPAR7: 001541R5: 141724 FAC1H: 00000000000 KIPDR7: 077506 SIPDR7: 000000 UIPDR7: 066016SP: 141710 FAC1L: 00000000000 KDPAR0: 000000 SDPAR0: 000000 UDPAR0: 001714R00: 140004 FAC2H: 00000000000 KDPDR0: 077506 SDPDR0: 000000 UDPDR0: 000006R01: 034272 FAC2L: 00000000000 KDPAR1: 000200 SDPAR1: 000000 UDPAR1: 000000R02: 005336 FAC3H: 00000000000 KDPDR1: 077506 SDPDR1: 000000 UDPDR1: 000000R03: 000200 FAC3L: 00000000000 KDPAR2: 000400 SDPAR2: 000000 UDPAR2: 000000R04: 000000 FAC4H: 00000000000 KDPDR2: 077506 SDPDR2: 000000 UDPDR2: 000000R05: 141724 FAC4L: 00000000000 KDPAR3: 000600 SDPAR3: 000000 UDPAR3: 000000R10: 000000 FAC5H: 00000000000 KDPDR3: 077406 SDPDR3: 000000 UDPDR3: 000000R11: 000000 FAC5L: 00000000000 KDPAR4: 001000 SDPAR4: 000000 UDPAR4: 000000R12: 000000 FPS: 000004 KDPDR4: 077406 SDPDR4: 000000 UDPDR4: 000000R13: 000000 FEA: 000000 KDPAR5: 001200 SDPAR5: 000000 UDPAR5: 000000R14: 000000 FEC: 00 KDPDR5: 077406 SDPDR5: 000000 UDPDR5: 000000R15: 000000 MMR0: 000201 KDPAR6: 001171 SDPAR6: 000000 UDPAR6: 000000KSP: 141710 MMR1: 000000 KDPDR6: 077506 SDPDR6: 000000 UDPDR6: 000000SSP: 000000 MMR2: 021626 KDPAR7: 007600 SDPAR7: 000000 UDPAR7: 001541USP: 177756 MMR3: 000005 KDPDR7: 077506 SDPDR7: 000000 UDPDR7: 066016PSW: 030000 KIPAR0: 000000 SIPAR0: 003612 UIPAR0: 001714 IREQ[0]: 00000000000CM: 0 KIPDR0: 077406 SIPDR0: 000106 UIPDR0: 000006 TRAPS: 00000PM: 3 KIPAR1: 000416 SIPAR1: 003700 UIPAR1: 000000 WAIT: 1RS: 0 KIPDR1: 077506 SIPDR1: 000106 UIPDR1: 000000 STOP_TRAPS: 00001FPD: 0 KIPAR2: 000616 SIPAR2: 000000 UIPAR2: 000000 STOP_VECA: 1IPL: 0 KIPDR2: 077506 SIPDR2: 000000 UIPDR2: 000000 STOP_SPA: 1T: 0 KIPAR3: 001016 SIPAR3: 000000 UIPAR3: 000000 PCQ[0]: 034412N: 0 KIPDR3: 077506 SIPDR3: 000000 UIPDR3: 000000 WRU: 005Z: 0 KIPAR4: 001216 SIPAR4: 000000 UIPAR4: 0000002012/3/24 129
  • 必要な内容に絞り込むPC,R0~R5,SP(KSP,USP)PSWKDPAR0~7UDPAR0~7PC: 021630 V: 0 KIPDR4: 077406 SIPDR4: 000000 UIPDR4: 000000R0: 140004 C: 0 KIPAR5: 001416 SIPAR5: 000000 UIPAR5: 000000R1: 034272 PIRQ: 000000 KIPDR5: 077406 SIPDR5: 000000 UIPDR5: 000000R2: 005336 STKLIM: 000000 KIPAR6: 001616 SIPAR6: 000000 UIPAR6: 000000R3: 000200 FAC0H: 00000000000 KIPDR6: 077406 SIPDR6: 000000 UIPDR6: 000000R4: 000000 FAC0L: 00000000000 KIPAR7: 007600 SIPAR7: 000000 UIPAR7: 001541R5: 141724 FAC1H: 00000000000 KIPDR7: 077506 SIPDR7: 000000 UIPDR7: 066016SP: 141710 FAC1L: 00000000000 KDPAR0: 000000 SDPAR0: 000000 UDPAR0: 001714R00: 140004 FAC2H: 00000000000 KDPDR0: 077506 SDPDR0: 000000 UDPDR0: 000006R01: 034272 FAC2L: 00000000000 KDPAR1: 000200 SDPAR1: 000000 UDPAR1: 000000R02: 005336 FAC3H: 00000000000 KDPDR1: 077506 SDPDR1: 000000 UDPDR1: 000000R03: 000200 FAC3L: 00000000000 KDPAR2: 000400 SDPAR2: 000000 UDPAR2: 000000R04: 000000 FAC4H: 00000000000 KDPDR2: 077506 SDPDR2: 000000 UDPDR2: 000000R05: 141724 FAC4L: 00000000000 KDPAR3: 000600 SDPAR3: 000000 UDPAR3: 000000R10: 000000 FAC5H: 00000000000 KDPDR3: 077406 SDPDR3: 000000 UDPDR3: 000000R11: 000000 FAC5L: 00000000000 KDPAR4: 001000 SDPAR4: 000000 UDPAR4: 000000R12: 000000 FPS: 000004 KDPDR4: 077406 SDPDR4: 000000 UDPDR4: 000000R13: 000000 FEA: 000000 KDPAR5: 001200 SDPAR5: 000000 UDPAR5: 000000R14: 000000 FEC: 00 KDPDR5: 077406 SDPDR5: 000000 UDPDR5: 000000R15: 000000 MMR0: 000201 KDPAR6: 001171 SDPAR6: 000000 UDPAR6: 000000KSP: 141710 MMR1: 000000 KDPDR6: 077506 SDPDR6: 000000 UDPDR6: 000000SSP: 000000 MMR2: 021626 KDPAR7: 007600 SDPAR7: 000000 UDPAR7: 001541USP: 177756 MMR3: 000005 KDPDR7: 077506 SDPDR7: 000000 UDPDR7: 066016PSW: 030000 KIPAR0: 000000 SIPAR0: 003612 UIPAR0: 001714 IREQ[0]: 00000000000CM: 0 KIPDR0: 077406 SIPDR0: 000106 UIPDR0: 000006 TRAPS: 00000PM: 3 KIPAR1: 000416 SIPAR1: 003700 UIPAR1: 000000 WAIT: 1RS: 0 KIPDR1: 077506 SIPDR1: 000106 UIPDR1: 000000 STOP_TRAPS: 00001FPD: 0 KIPAR2: 000616 SIPAR2: 000000 UIPAR2: 000000 STOP_VECA: 1IPL: 0 KIPDR2: 077506 SIPDR2: 000000 UIPDR2: 000000 STOP_SPA: 1T: 0 KIPAR3: 001016 SIPAR3: 000000 UIPAR3: 000000 PCQ[0]: 034412N: 0 KIPDR3: 077506 SIPDR3: 000000 UIPDR3: 000000 WRU: 005Z: 0 KIPAR4: 001216 SIPAR4: 000000 UIPAR4: 0000002012/3/24 130
  • レジスタの指定方法Stateの表示順に’-’で範囲を指定sim> e pc-spPC: 021630R0: 140004R1: 034272R2: 005336R3: 000200R4: 000000R5: 141724SP: 1417102012/3/24 131
  • MMUレジスタの指定方法Stateの表示順に’-’で範囲を指定sim> e KDPAR0-KDPDR7KDPAR0: 000000KDPDR0: 077506KDPAR1: 000200KDPDR1: 077506 Pdp11/40では、KDPAR2: 000400KDPDR2: 077506 KPAR,KPDRと呼んでいKDPAR3:KDPDR3: 000600 077406 たが、simhでは上位機種KDPAR4: 001000 のレジスタ名で表示されKDPDR4: 077406KDPAR5: 001200 るので、KDPAR,KDPDRKDPDR5:KDPAR6: 077406 001171 と読み替えるKDPDR6: 077506KDPAR7: 007600KDPDR7: 0775062012/3/24 132
  • メモリの調べ方sim> e 0 // アドレス0を表示0: 000417sim> e 0/4 // アドレス0から4バイトを表示0: 0004172: 000004sim> e 0-2 // アドレス0から2までを表示0: 0004172: 0000042012/3/24 133
  • 表示フォーマットの指定-a ASCIIで表示-c 文字列で表示-m 命令列で表示-o 8進で表示-x 16進で表示sim> e -m 54104/2054104: 00001354106: MOV R0,-(SP)54110: BIC #177400,(SP)54114: JSR PC,@#2210054120: ADD #6,SP2012/3/24 134
  • シンボルからアドレスを調べるsim> c //unixに戻る# nm /unix | grep main // mainのアドレス022272T _main# nm /unix | grep proc034476T _newproc005206B _proc043170T _procxmt2012/3/24 135
  • mainでbreakしてMMUを調べるsim> break 022272sim> boot rk0@unixBreakpoint, PC: 022272 (JSR R5,22240)sim> e KDPAR0-KDPDR7KDPAR0: 000000KDPDR0: 077506KDPAR1: 000200KDPDR1: 077506KDPAR2: 000400KDPDR2: 077506KDPAR3: 000600KDPDR3: 077406KDPAR4: 001000KDPDR4: 077406KDPAR5: 001200KDPDR5: 077406KDPAR6: 001171KDPDR6: 077506KDPAR7: 007600KDPDR7: 077506sim>2012/3/24 136
  • 自分のprocを見る#1# nm /unix | grep _write054124T _write Shellが#をwriteする箇所(カーネ031700T _writei ルのエントリ)でbreakする050176T _writep#Simulation stopped, PC: 021630 (MOV (SP)+,177776)sim> break 54124sim> c[Enter]Breakpoint, PC: 054124 (JSR R5,22240)sim>2012/3/24 137
  • 自分のprocを見る#2 procのアドレスはu.u_procpでわかる uは常にカーネル仮想の140000番地 一方でsimhのdebug機能は仮想アドレスを扱 えない 自分で変換するsim> e KDPAR6KDPAR6: 001477 // 64バイトを1単位とした値 64バイト=6ビットシフト=8進数で00 Userは00147700にあるはず2012/3/24 138
  • 自分のprocを見る#3 sim> e 147700/100147700: 141746 u_rsav[0]147702: 141756 u_rsav[1]147704: 000200 u_fsav[0] 0413: struct user 0414: {147706: 000000 1 0415: int u_rsav[2]; /* save r5,r6 when exchanging stacks */147710: 000000 2 0416: int u_fsav[25]; /* save fp registers */ 0417: /* rsav and fsav must be first in structure */147712: 000000 3 0418: char u_segflg; /* flag for IO; user or kernel space */ 0419: char u_error; /* return error code */147714: 000000 4 0420: char u_uid; /* effective user id */ 0421: char u_gid; /* effective group id */147716: 000000 5 0422: char u_ruid; /* real user id */ 0423: char u_rgid; /* real group id */ : 0424: int u_procp; /* pointer to proc structure */ :147764: 000000 24147766: 000000 u_segflag/u_error147770: 001400 u_uid/u_gid147772: 001400 u_ruid/u_rgid147774: 005262 u_procp147776: 1777372012/3/24 139
  • 自分のprocを見る#4sim> e -h 5262/405262: 0103 p_flag/p_stat 0358: struct proc5264: 0064 p_sig/p_pri 0359: {5266: 7F00 p_time/p_uid 0360: char p_stat;5270: 0000 p_cpu 0361: char p_flag; 0362: char p_pri; /* priority, negative is high */5272: 42F2 p_ttyp 0363: char p_sig; /* signal number sent to this process *5274: 000E p_pid 0364: char p_uid; /* user id, used to direct tty signals */ 0365: char p_time; /* resident time for scheduling */5276: 0001 p_ppid 0366: char p_cpu; /* cpu usage for scheduling */5300: 033F 0367: char p_nice; /* nice for scheduling */5302: 0048 0368: int p_ttyp; /* controlling tty */ 0369: int p_pid; /* unique process id */5304: 0000 0370: int p_ppid; /* process id of parent */5306: 0EDC 0371: int p_addr; /* address of swappable image */ 0372: int p_size; /* size of swappable image (*64 bytes)5310: 0000 0373: int p_wchan; /* event process is awaiting */5312: 00CE 0374: int *p_textp; /* pointer to text structure */ 0375:5314: 0000 pidは0xe=14(10進) 0376: } proc[NPROC];5316: 00005320: 00002012/3/24 140
  • 自分のprocを見る#5Breakpoint, PC: 054104 (JSR R5,22240)sim> nobreak 54104sim> c# ps 14 - 29 ps# pidは0xe=14(10進)2012/3/24 141
  • だらだらつづくよ2012/3/24 142