UNIX V6 セミナー (4)
@magoroku15
2013/5/11
今日の内容
• 過去:UNIX v6, 未来:4.4BSDとの関連
• 仮想記憶の空間構成
• スワッピングとページング
• 4.3BSDを例にした仮想記憶管理の解析
• 参考資料
– Freebsd-53-kernel-mm.pptx 七誌さん
過去:UNIX V6, 未来:4.4BSDとの関連
4.3BSD
カーネルのメモリ構成
※アドレスは上を0としたため、本とは上下反転
カーネル
ユーザー
0
4GB
1. 常駐型
FreeBSDなど
カーネルユーザー
2. 切替型
UNIX V6など
http://sdrv.ms/160BJhK より
常駐型
カーネル
プロセスA
0
4GB
永続マップカーネル
プロセスB
• カーネルが同じアドレスに常駐する
タスクスイッチで入替
http://sdrv.ms/160BJhK より
切替型
0
4GB
カーネルプロセスA
• 広いメモリ空間を使うことができる
プロセスB
http://sdrv.ms/160BJhK より
データの受け渡し
カーネル
ユーザー
0
4GB
1. 常駐型
直接参照(高速)
2. 切替型
特殊命令でコピー(遅い)
カーネルユーザー
※カーネルは自由にユーザーのメモリを読めるが、逆は不可
http://sdrv.ms/160BJhK より
メモリ管理から見た4.3BSDの特徴
• UNIX v{6|7}の空間を切り替え型から常駐型に変更
• On demand paging
– clock algorithm
• One handからTwo handへの変更
• 共有メモリはtextのみ
– COW, shm, 動的なbufなどは存在しない
• 限定的なカーネルメモリアロケータ
– mbufのみ
• VAX-11依存の実装
– PTEにOSの管理情報を置く
– 参照ビットのエミュレーション
4.3BSDを理解する意味
• UNIXの系譜では第2世代の最後
– 第一世代 UNIX v{6|7} 切り替え型
– 第二世代 UNIX 32v~4.3BSD 常駐型
– 第三世代 Mach, 4.4BSD他 +広義の単一レベル記憶
• 仮想空間にvnode,offsetで表現可能なファイルをマップ可能になる
• 次の事項の理解に有用
– MMUの仕組み
– ページングの原理と実装
– 実メモリ管理
• UNIX v{6|7}の構成の変化は少なく連続性がある
– ファイル構成・関数構成
仮想記憶の空間構成
空間の構成
• 単一仮想空間
– 一枚の空間を仮想化する
– 一枚の空間に複数のプロセスが同居
– メモリの拡張が主な目的
• 多重仮想空間
– 複数の空間を仮想化する
– 一枚の空間に1個のプロセスを配置
– システムの保護
空間構成
多重仮想空間
単一仮想空間
多重仮想空間の管理構造
ユーザ
物理メモリ管理構造
仮想-物理アドレス変換表
カーネル
アドレス変換機構
• アドレスの変換単
位はページ
– 数Kbyte程度
– Aligned
• アドレスの変換表を
OSが用意して
CPU(MMU)に通知
• MMUが仮想アドレ
スを実アドレスに変
換
変換表
CR
アドレス変換表
アドレスと変換表の関係
2レベル変換表
仮想空間の利点
• 複数の独立したアドレス空間
– アドレス空間の間でメモリの書き換え・参照ができな
い
– プログラムAのバグがプログラムBに影響を与えない
– プログラムAのメモリをプログラムBから参照できない
• 全てのプログラムが同じアドレスを利用可能
– リロケータブルである必要がない
– コンパイラ・リンカの負担が少ない
スワッピングとページング
スワッピング
• スワップアウト
– 最も優先度の低いプログラムを選択し
– プログラムをスケジュールの対象から外す
– プログラムのメモリ全体をスワップデバイスに退避(write)
• スワップイン
– 実行するプロセスがスワップアウトさせていたら
– メモリを確保-不足したら他のプロセスをスワップアウト
– スワップデバイスに退避してあるメモリイメージをメモリに復元
(read)
– プログラムをスケジュールの対象に含める
• スワッピングとページングは明確に区別せずに使われる
場合があるので注意
スワッピングの特徴
• プログラム全体を退避・復元
– アドレス空間の拡張に伴ってI/O量が増加
– 大きなコストを払ってスワップインしても、その後
の挙動は予想できない
• メモリ・フラグメンテーションの解消手段
– UNIX v6等の実装
• ページングと比較してハードウェアの負担が
少ない
ページング
• ページアウト
1. メモリが不足
2. 最近使われていない物理メモリ(ページ)を特定
3. 物理メモリが仮想メモリとして利用されていたら変換対象から
外す
4. 物理メモリをページングデバイスに退避
• ページイン
1. 割り当て済の仮想メモリをプログラムが参照
2. アドレス変換例外で割り込みが発生しOSに制御が移る
3. OSが該当プロセス+アドレスから退避済の物理メモリ(ページ)
を特定する
4. 物理メモリを読み込んで仮想メモリから変換可能とする
5. 割り込みから復帰
ページングの特徴
• 一般的な運用では
– 仮想空間の総量 > 物理メモリ
– 物理メモリの奪い合い
– メモリ参照に局所性が有る場合
• ゆっくり奪い合う→変換例外とその対応のコストは無視できる
– メモリ参照に局所性が無い場合
• はげしく奪い合う→変換例外とその対応コストが無視できない
• 局所的な参照を前提として使われていないメモリの特
定が必要
– 最近利用されていないメモリは将来も利用されない可能
性が高い
– どうやって?
LRU - Least Recently Used
• 「最近使われていないメモリは、将来も使わ
れない可能性が高い」事を前提とする
• メモリの参照頻度を記録して、最近使われて
いないメモリを予想する
– 近年のCPUは参照の有無をアドレス変換表にHW
が記録する
• X86, ARMなど (除くVAX-11)
• 多くは1bit(参照の有無)のみを記録
仮想記憶の構成
4.3BSDを例に
解析の対象
• 4.3BSD
– 1986年、カルフォルニア大学バークレー校で開
発・配布された近代UNIX
– 仮想記憶・TCP/IP・拡張ファイルシステムが特徴
– ソースの入手にはAT&T UNIXのライセンスが必要
– 今回は以下を利用
http://www.tamacom.com/tour-j.html
4.3BSD VAX-11の空間構成
• 32bit = 4Gbyteの空間を4分割(4セグメント)
unused
kernel
User stack
User Text
User Data
0x4000.000
0x0000.000
0x8000.000
0xC000.000
0xFFFF.FFFF
P0
P1
System
Reserved
• P0,P1 にUserプログラム
• P1にはKernel Stack・Uも配置
• System リージョンにカーネルを配置
• copy{in|out}は同一空間の転送
1142 /*
1143 * Copy specified amount of data from user space into the kernel
1144 * Copyin(from, to, len)
1145 * r1 == from (user source address)
1146 * r3 == to (kernel destination address)
1147 * r5 == length
1148 */
1149 .align 1
1150 JSBENTRY(Copyin, R1|R3|R5)
1151 cmpl r5,$(NBPG*CLSIZE) # probing one page or less ?
1152 bgtru 1f # no
1153 prober $3,r5,(r1) # bytes accessible ?
1154 beql ersb # no
1155 movc3 r5,(r1),(r3)
1156 /* clrl r0 # redundant */
1157 rsb
VAX-11の仮想記憶
• 512byte/1ページ 9bit
• 32bitのアドレス幅上位2bitがリージョン
– P0=00,P1=01,S=10
32bit
Page offset
9bit
Segmant
2bit
Virtual Page Number
21bit
セグメントとページテーブル
• 各セグメントはPTEの配列=ページテーブルと
して表現
– セグメントベースレジスタ:SEGBR
– セグメントリミットレジスタ:SEGLR
• 各リージョンは2^21個のページを持つ
– 1リージョン8MBのページテーブルが必要
– P0,P1,Sで24Mbyte/プロセス必要
– P0,P1のページテーブルはSのカーネル仮想に配
置
セグメント用のレジスタ
• root/machine/mtpr.h
18 #define P0BR 0x8 /* p0 base register */
19 #define P0LR 0x9 /* p0 length register */
20 #define P1BR 0xa /* p1 base register */
21 #define P1LR 0xb /* p1 length register */
22 #define SBR 0xc /* system segment base register */
23 #define SLR 0xd /* system segment length register */
unused
kernel
User stack
Kernal stack
User Text
User Data
P0BR
P1BR
SBR
P0LR
P1LR
SLR
セグメントレジスタの設定
• root/GENERIC/sys/vmmac.h
88 #define setp0br(x) (u.u_pcb.pcb_p0br = (x), mtpr(P0BR, x))
89 #define setp0lr(x) (u.u_pcb.pcb_p0lr = ¥
90 (x) | (u.u_pcb.pcb_p0lr & AST_CLR), ¥
91 mtpr(P0LR, x))
92 #define setp1br(x) (u.u_pcb.pcb_p1br = (x), mtpr(P1BR, x))
93 #define setp1lr(x) (u.u_pcb.pcb_p1lr = (x), mtpr(P1LR, x))
94 #define initp1br(x) ((x) - P1PAGES)
UNIX v6がuにアドレス変換レジスタの内容を持っていたのと同じ
実メモリ(ページ)管理
4.3BSDを例に
構造:cmap
• h/cmap.h
27 struct cmap
28 {
29 unsigned short c_next, /* index of next free list entry */
30 c_prev, /* index of previous free list entry */
31 c_hlink; /* hash link for <blkno,mdev> */
32 unsigned short c_ndx; /* index of owner proc or text */
33 unsigned int c_page:21, /* virtual page number in segment */
34 c_lock:1, /* locked for raw i/o or pagein */
35 c_want:1, /* wanted */
36 c_intrans:1, /* intransit bit */
37 c_free:1, /* on the free list */
38 c_gone:1, /* associated page has been released */
39 c_type:2, /* type CSYS or CTEXT or CSTACK or CDATA */
40 :4, /* to longword boundary */
41 c_blkno:24, /* disk block this is a copy of */
42 c_mdev:8; /* which mounted dev this is from */
43 };
Cmapの初期化
• root/vax/machdep.c
105 v = (caddr_t)(0x80000000 | (firstaddr * NBPG));
106 #define valloc(name, type, num) ¥
107 (name) = (type *)v; v = (caddr_t)((name)+(num))
108 #define valloclim(name, type, num, lim) ¥
109 (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
110 valloclim(inode, struct inode, ninode, inodeNINODE);
111 valloclim(file, struct file, nfile, fileNFILE);
112 valloclim(proc, struct proc, nproc, procNPROC);
113 valloclim(text, struct text, ntext, textNTEXT);
114 valloc(cfree, struct cblock, nclist);
115 valloc(callout, struct callout, ncallout);
116 valloc(swapmap, struct map, nswapmap = nproc * 2);
117 valloc(argmap, struct map, ARGMAPSIZE);
118 valloc(kernelmap, struct map, nproc);
119 valloc(mbmap, struct map, nmbclusters/4);
120 valloc(namecache, struct namecache, nchsize);
177 ncmap = (maxmem*NBPG - ((int)(v + bufpages*CLBYTES) &~ 0x80000000)) /
178 (CLBYTES + sizeof(struct cmap)) + 2;
179 valloclim(cmap, struct cmap, ncmap, ecmap);
パラメタを参照して各構造を
割り当て(v6では配列だった)
現在のvからmaxmemまでの
アドレスに応じたcmapを確保
ページの割り当て:memall()
• sys/vm_mem.c
159 /*
160 * Allocate memory -
161 *
162 * The free list appears as a doubly linked list
163 * in the core map with cmap[0] serving as a header.
164 */
165 memall(pte, size, p, type)
/* */
166 register struct pte *pte;
167 int size;
168 struct proc *p;
169 {
186 for (i = size; i > 0; i -= CLSIZE) {
210 case CDATA:
211 rpte = dptopte(rp, c->c_page);
212 break;
213
222 switch (type) {
233 case CDATA:
234 c->c_page = vtodp(p, ptetov(p, pte));
235 c->c_ndx = p->p_ndx;
236 break;
272 pf = cmtopg(curpos);
273 for (j = 0; j < CLSIZE; j++)
274 *(int *)pte++ = pf++;
275 c->c_free = 0;
276 c->c_gone = 0;
277 if (c->c_intrans || c->c_want)
278 panic("memall intrans|want");
279 c->c_lock = 1;
280 c->c_type = type;
281 }
282 splx(s);
283 return (size);
284 }
ページング
構造:pte
• vax/pte.h
20 struct pte
21 {
22 unsigned int pg_pfnum:21, /* core page frame number or 0 */
23 :2,
24 pg_vreadm:1, /* modified since vread (or with _m) */
25 pg_swapm:1, /* have to write back to swap */
26 pg_fod:1, /* is fill on demand (=0) */
27 pg_m:1, /* hardware maintained modified bit */
28 pg_prot:4, /* access control */
29 pg_v:1; /* valid bit */
30 };
pfnumV prot M 0 soft
59 #define PG_NOACC 0
60 #define PG_KW 0x10000000
61 #define PG_KR 0x18000000
62 #define PG_UW 0x20000000
63 #define PG_URKW 0x70000000
64 #define PG_URKR 0x78000000
処理:pageout()
• sys/vm_page.c +696
696 loop:
705 (void) splbio();
706 if (bclnlist != NULL) {
707 (void) spl0();
708 cleanup();
709 goto loop;
710 }
711 sleep((caddr_t)&proc[2], PSWP+1);
712 (void) spl0();
713 count = 0;
714 pushes = 0;
715 while (nscan < desscan && freemem < lotsfree) {
720 if (checkpage(fronthand, FRONT))
721 count = 0;
722 if (checkpage(backhand, BACK))
723 count = 0;
724 cnt.v_scan++;
725 nscan++;
726 if (++fronthand >= maxhand) {
727 fronthand = 0;
728 cnt.v_rev++;
729 if (count > 2) {
735 goto loop;
736 }
737 count++;
738 }
739 if (++backhand >= maxhand)
740 backhand = 0;
741 }
742 goto loop;
proc[2]はpager,メモリが不足すると
wakeupされる
Fronthand.backhandを++しながら一
定のpageをスキャンする
fronthand
backhand
maxhand/0
cmap[hand]がcheckの対象
処理:checkpage()
• sys/vm_page.c +774
774 c = &cmap[hand];
775 if (c->c_lock || c->c_free)
776 return (0);
777 switch (c->c_type) {
779 case CSYS:
780 return (0);
782 case CTEXT:
783 xp = &text[c->c_ndx];
784 rp = xp->x_caddr;
785 v = tptov(rp, c->c_page);
786 pte = tptopte(rp, c->c_page);
787 break;
789 case CDATA:
790 case CSTACK:
791 rp = &proc[c->c_ndx];
792 while (rp->p_flag & SNOVM)
793 rp = rp->p_xlink;
794 xp = rp->p_textp;
795 if (c->c_type == CDATA) {
796 v = dptov(rp, c->c_page);
797 pte = dptopte(rp, c->c_page);
798 } else {
799 v = sptov(rp, c->c_page);
800 pte = sptopte(rp, c->c_page);
801 }
802 break;
803 }
cmapのc_typeに用途が記録
実メモリcmap[hand]が参照している
pteを特定
プロセス空間と物理メモリの関連
cmap[] 物理メモリproc []
c_ndx
c_ndx
p_tsize
p_p0br
c_page
cmap[n]
proc[m]
User stack
User Text
User Data
0x4000.000
0x0000.000
0x8000.000
P0
P1
#define dptov(p, i) ((unsigned)(stoc(ctos((p)->p_tsize)) + (i)))
#define dptopte(p, i) ((p)->p_p0br + ((p)->p_tsize + (i)))
pte[]
処理:checkpage()
• sys/vm_page.c +813
813 if (pte->pg_v) {
814 if (whichhand == BACK)
815 return(0);
816 pte->pg_v = 0;
817 if (anycl(pte, pg_m))
818 pte->pg_m = 1;
819 distcl(pte);
820 if (c->c_type == CTEXT)
821 distpte(xp, (unsigned)vtotp(rp, v), pte);
822 if ((rp->p_flag & (SSEQL|SUANOM)) == 0 &&
823 rp->p_rssize <= rp->p_maxrss)
824 return (0);
825 }
処理:checkpage()
• sys/vm_page.c +850
850 if (dirtycl(pte)) {
856 if (rp->p_flag & (SLOCK|SWEXIT))
857 return (0);
858 /*
859 * Limit pushes to avoid saturating
860 * pageout device.
861 */
862 if (pushes > maxpgio / RATETOSCHEDPAGING)
863 return (0);
864 pushes++;
882 loop2:
883 (void) splbio();
884 if (bclnlist != NULL) {
885 (void) spl0();
886 cleanup();
887 goto loop2;
888 }
889 if (bswlist.av_forw == NULL) {
890 bswlist.b_flags |= B_WANTED;
891 sleep((caddr_t)&proc[2], PSWP+2);
892 (void) spl0();
900 goto top;
901 }
902 (void) spl0();
904 MLOCK(c);
905 uaccess(rp, Pushmap, &pushutl);
909 pte->pg_m = 0;
910 distcl(pte);
911 if (c->c_type == CTEXT) {
912 xp->x_poip++;
913 distpte(xp, (unsigned)vtotp(rp, v), pte);
914 } else
915 rp->p_poip++;
916 v = kluster(rp, v, pte, B_WRITE, &klsize, klout,
(daddr_t)0);
917 if (klsize == 0)
918 panic("pageout klsize");
919 daddr = vtod(rp, v, &pushutl.u_dmap,
&pushutl.u_smap);
920 (void)swap(rp, daddr, ptob(v), klsize * ctob(CLSIZE),
921 B_WRITE, B_DIRTY, swapdev, pte->pg_pfnum);
929 return (1); /* well, it'll be free soon */
930
931 }
アドレス変換例外
• machine/trap.c
58 trap(sp, type, code, pc, psl)
59 int sp, type;
60 unsigned code;
61 int pc, psl;
73 switch (type) {
75 default:
76 printf("trap type %d, code = %x, pc = %x¥n", type, code, pc);
77 type &= ~USER;
78 if ((unsigned)type < TRAP_TYPES)
79 panic(trap_type[type]);
80 panic("trap");
82 case T_PROTFLT+USER: /* protection fault */
83 i = SIGBUS;
84 break;
119
120 case T_PAGEFLT: /* allow page faults in kernel mode */
121 case T_PAGEFLT+USER: /* page fault */
122 i = u.u_error;
123 pagein(code, 0);
124 u.u_error = i;
125 if (type == T_PAGEFLT)
126 return;
127 goto out;
処理:pagein()
• sys/vm_page.c
68 pagein(virtaddr, dlyu)
100 vsave = v = clbase(btop(virtaddr));
101 p = u.u_procp;
108 pte = vtopte(p, v);
198 bnswap = bncache = bn = vtod(p, v, &u.u_dmap,
&u.u_smap);
199 dev = swapdev;
219 opte = *pte;
311 pte->pg_prot = opte.pg_prot;
314 distcl(pte);
377 /*
378 * Fill from swap area. Try to find adjacent
379 * pages to bring in also.
380 */
381 v = kluster(p, v, pte, B_READ, &klsize,
382 (type == CTEXT) ? kltxt :
383 ((p->p_flag & SSEQL) ? klseql : klin), bn);
384 splx(sk);
385 /* THIS COULD BE COMPUTED INCREMENTALLY... */
386 bncache = bn = vtod(p, v, &u.u_dmap, &u.u_smap);
387 }
388
389 distcl(pte);
390 swerror = swap(p, bn, ptob(v), klsize * ctob(CLSIZE),
391 B_READ, B_PGIN, dev, 0);
!NOTICE!
第三世代UNIX
• Mach由来の仮想記憶に置き換え
– 仮想記憶は
• f(vnode, offset) → (p, vaddr)
• f(p, vaddr) → (vnode,offset)
– 広範囲に影響
• 共用テキスト
• 共有メモリ
• バッファキャッシュ
• Demand loading
• ForkのCopy On Write化
• Linux,Solaris,BSDで実装は異なるが、考え方は同じ

仮想記憶入門 BSD-4.3を例題に

  • 1.
    UNIX V6 セミナー(4) @magoroku15 2013/5/11
  • 2.
    今日の内容 • 過去:UNIX v6,未来:4.4BSDとの関連 • 仮想記憶の空間構成 • スワッピングとページング • 4.3BSDを例にした仮想記憶管理の解析 • 参考資料 – Freebsd-53-kernel-mm.pptx 七誌さん
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
    メモリ管理から見た4.3BSDの特徴 • UNIX v{6|7}の空間を切り替え型から常駐型に変更 •On demand paging – clock algorithm • One handからTwo handへの変更 • 共有メモリはtextのみ – COW, shm, 動的なbufなどは存在しない • 限定的なカーネルメモリアロケータ – mbufのみ • VAX-11依存の実装 – PTEにOSの管理情報を置く – 参照ビットのエミュレーション
  • 9.
    4.3BSDを理解する意味 • UNIXの系譜では第2世代の最後 – 第一世代UNIX v{6|7} 切り替え型 – 第二世代 UNIX 32v~4.3BSD 常駐型 – 第三世代 Mach, 4.4BSD他 +広義の単一レベル記憶 • 仮想空間にvnode,offsetで表現可能なファイルをマップ可能になる • 次の事項の理解に有用 – MMUの仕組み – ページングの原理と実装 – 実メモリ管理 • UNIX v{6|7}の構成の変化は少なく連続性がある – ファイル構成・関数構成
  • 10.
  • 11.
    空間の構成 • 単一仮想空間 – 一枚の空間を仮想化する –一枚の空間に複数のプロセスが同居 – メモリの拡張が主な目的 • 多重仮想空間 – 複数の空間を仮想化する – 一枚の空間に1個のプロセスを配置 – システムの保護
  • 12.
  • 13.
  • 14.
    アドレス変換機構 • アドレスの変換単 位はページ – 数Kbyte程度 –Aligned • アドレスの変換表を OSが用意して CPU(MMU)に通知 • MMUが仮想アドレ スを実アドレスに変 換 変換表 CR
  • 15.
  • 16.
  • 17.
  • 18.
    仮想空間の利点 • 複数の独立したアドレス空間 – アドレス空間の間でメモリの書き換え・参照ができな い –プログラムAのバグがプログラムBに影響を与えない – プログラムAのメモリをプログラムBから参照できない • 全てのプログラムが同じアドレスを利用可能 – リロケータブルである必要がない – コンパイラ・リンカの負担が少ない
  • 19.
  • 20.
    スワッピング • スワップアウト – 最も優先度の低いプログラムを選択し –プログラムをスケジュールの対象から外す – プログラムのメモリ全体をスワップデバイスに退避(write) • スワップイン – 実行するプロセスがスワップアウトさせていたら – メモリを確保-不足したら他のプロセスをスワップアウト – スワップデバイスに退避してあるメモリイメージをメモリに復元 (read) – プログラムをスケジュールの対象に含める • スワッピングとページングは明確に区別せずに使われる 場合があるので注意
  • 21.
    スワッピングの特徴 • プログラム全体を退避・復元 – アドレス空間の拡張に伴ってI/O量が増加 –大きなコストを払ってスワップインしても、その後 の挙動は予想できない • メモリ・フラグメンテーションの解消手段 – UNIX v6等の実装 • ページングと比較してハードウェアの負担が 少ない
  • 22.
    ページング • ページアウト 1. メモリが不足 2.最近使われていない物理メモリ(ページ)を特定 3. 物理メモリが仮想メモリとして利用されていたら変換対象から 外す 4. 物理メモリをページングデバイスに退避 • ページイン 1. 割り当て済の仮想メモリをプログラムが参照 2. アドレス変換例外で割り込みが発生しOSに制御が移る 3. OSが該当プロセス+アドレスから退避済の物理メモリ(ページ) を特定する 4. 物理メモリを読み込んで仮想メモリから変換可能とする 5. 割り込みから復帰
  • 23.
    ページングの特徴 • 一般的な運用では – 仮想空間の総量> 物理メモリ – 物理メモリの奪い合い – メモリ参照に局所性が有る場合 • ゆっくり奪い合う→変換例外とその対応のコストは無視できる – メモリ参照に局所性が無い場合 • はげしく奪い合う→変換例外とその対応コストが無視できない • 局所的な参照を前提として使われていないメモリの特 定が必要 – 最近利用されていないメモリは将来も利用されない可能 性が高い – どうやって?
  • 24.
    LRU - LeastRecently Used • 「最近使われていないメモリは、将来も使わ れない可能性が高い」事を前提とする • メモリの参照頻度を記録して、最近使われて いないメモリを予想する – 近年のCPUは参照の有無をアドレス変換表にHW が記録する • X86, ARMなど (除くVAX-11) • 多くは1bit(参照の有無)のみを記録
  • 25.
  • 26.
    解析の対象 • 4.3BSD – 1986年、カルフォルニア大学バークレー校で開 発・配布された近代UNIX –仮想記憶・TCP/IP・拡張ファイルシステムが特徴 – ソースの入手にはAT&T UNIXのライセンスが必要 – 今回は以下を利用 http://www.tamacom.com/tour-j.html
  • 27.
    4.3BSD VAX-11の空間構成 • 32bit= 4Gbyteの空間を4分割(4セグメント) unused kernel User stack User Text User Data 0x4000.000 0x0000.000 0x8000.000 0xC000.000 0xFFFF.FFFF P0 P1 System Reserved • P0,P1 にUserプログラム • P1にはKernel Stack・Uも配置 • System リージョンにカーネルを配置 • copy{in|out}は同一空間の転送 1142 /* 1143 * Copy specified amount of data from user space into the kernel 1144 * Copyin(from, to, len) 1145 * r1 == from (user source address) 1146 * r3 == to (kernel destination address) 1147 * r5 == length 1148 */ 1149 .align 1 1150 JSBENTRY(Copyin, R1|R3|R5) 1151 cmpl r5,$(NBPG*CLSIZE) # probing one page or less ? 1152 bgtru 1f # no 1153 prober $3,r5,(r1) # bytes accessible ? 1154 beql ersb # no 1155 movc3 r5,(r1),(r3) 1156 /* clrl r0 # redundant */ 1157 rsb
  • 28.
    VAX-11の仮想記憶 • 512byte/1ページ 9bit •32bitのアドレス幅上位2bitがリージョン – P0=00,P1=01,S=10 32bit Page offset 9bit Segmant 2bit Virtual Page Number 21bit
  • 29.
    セグメントとページテーブル • 各セグメントはPTEの配列=ページテーブルと して表現 – セグメントベースレジスタ:SEGBR –セグメントリミットレジスタ:SEGLR • 各リージョンは2^21個のページを持つ – 1リージョン8MBのページテーブルが必要 – P0,P1,Sで24Mbyte/プロセス必要 – P0,P1のページテーブルはSのカーネル仮想に配 置
  • 30.
    セグメント用のレジスタ • root/machine/mtpr.h 18 #defineP0BR 0x8 /* p0 base register */ 19 #define P0LR 0x9 /* p0 length register */ 20 #define P1BR 0xa /* p1 base register */ 21 #define P1LR 0xb /* p1 length register */ 22 #define SBR 0xc /* system segment base register */ 23 #define SLR 0xd /* system segment length register */ unused kernel User stack Kernal stack User Text User Data P0BR P1BR SBR P0LR P1LR SLR
  • 31.
    セグメントレジスタの設定 • root/GENERIC/sys/vmmac.h 88 #definesetp0br(x) (u.u_pcb.pcb_p0br = (x), mtpr(P0BR, x)) 89 #define setp0lr(x) (u.u_pcb.pcb_p0lr = ¥ 90 (x) | (u.u_pcb.pcb_p0lr & AST_CLR), ¥ 91 mtpr(P0LR, x)) 92 #define setp1br(x) (u.u_pcb.pcb_p1br = (x), mtpr(P1BR, x)) 93 #define setp1lr(x) (u.u_pcb.pcb_p1lr = (x), mtpr(P1LR, x)) 94 #define initp1br(x) ((x) - P1PAGES) UNIX v6がuにアドレス変換レジスタの内容を持っていたのと同じ
  • 32.
  • 33.
    構造:cmap • h/cmap.h 27 structcmap 28 { 29 unsigned short c_next, /* index of next free list entry */ 30 c_prev, /* index of previous free list entry */ 31 c_hlink; /* hash link for <blkno,mdev> */ 32 unsigned short c_ndx; /* index of owner proc or text */ 33 unsigned int c_page:21, /* virtual page number in segment */ 34 c_lock:1, /* locked for raw i/o or pagein */ 35 c_want:1, /* wanted */ 36 c_intrans:1, /* intransit bit */ 37 c_free:1, /* on the free list */ 38 c_gone:1, /* associated page has been released */ 39 c_type:2, /* type CSYS or CTEXT or CSTACK or CDATA */ 40 :4, /* to longword boundary */ 41 c_blkno:24, /* disk block this is a copy of */ 42 c_mdev:8; /* which mounted dev this is from */ 43 };
  • 34.
    Cmapの初期化 • root/vax/machdep.c 105 v= (caddr_t)(0x80000000 | (firstaddr * NBPG)); 106 #define valloc(name, type, num) ¥ 107 (name) = (type *)v; v = (caddr_t)((name)+(num)) 108 #define valloclim(name, type, num, lim) ¥ 109 (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) 110 valloclim(inode, struct inode, ninode, inodeNINODE); 111 valloclim(file, struct file, nfile, fileNFILE); 112 valloclim(proc, struct proc, nproc, procNPROC); 113 valloclim(text, struct text, ntext, textNTEXT); 114 valloc(cfree, struct cblock, nclist); 115 valloc(callout, struct callout, ncallout); 116 valloc(swapmap, struct map, nswapmap = nproc * 2); 117 valloc(argmap, struct map, ARGMAPSIZE); 118 valloc(kernelmap, struct map, nproc); 119 valloc(mbmap, struct map, nmbclusters/4); 120 valloc(namecache, struct namecache, nchsize); 177 ncmap = (maxmem*NBPG - ((int)(v + bufpages*CLBYTES) &~ 0x80000000)) / 178 (CLBYTES + sizeof(struct cmap)) + 2; 179 valloclim(cmap, struct cmap, ncmap, ecmap); パラメタを参照して各構造を 割り当て(v6では配列だった) 現在のvからmaxmemまでの アドレスに応じたcmapを確保
  • 35.
    ページの割り当て:memall() • sys/vm_mem.c 159 /* 160* Allocate memory - 161 * 162 * The free list appears as a doubly linked list 163 * in the core map with cmap[0] serving as a header. 164 */ 165 memall(pte, size, p, type) /* */ 166 register struct pte *pte; 167 int size; 168 struct proc *p; 169 { 186 for (i = size; i > 0; i -= CLSIZE) { 210 case CDATA: 211 rpte = dptopte(rp, c->c_page); 212 break; 213 222 switch (type) { 233 case CDATA: 234 c->c_page = vtodp(p, ptetov(p, pte)); 235 c->c_ndx = p->p_ndx; 236 break; 272 pf = cmtopg(curpos); 273 for (j = 0; j < CLSIZE; j++) 274 *(int *)pte++ = pf++; 275 c->c_free = 0; 276 c->c_gone = 0; 277 if (c->c_intrans || c->c_want) 278 panic("memall intrans|want"); 279 c->c_lock = 1; 280 c->c_type = type; 281 } 282 splx(s); 283 return (size); 284 }
  • 36.
  • 37.
    構造:pte • vax/pte.h 20 structpte 21 { 22 unsigned int pg_pfnum:21, /* core page frame number or 0 */ 23 :2, 24 pg_vreadm:1, /* modified since vread (or with _m) */ 25 pg_swapm:1, /* have to write back to swap */ 26 pg_fod:1, /* is fill on demand (=0) */ 27 pg_m:1, /* hardware maintained modified bit */ 28 pg_prot:4, /* access control */ 29 pg_v:1; /* valid bit */ 30 }; pfnumV prot M 0 soft 59 #define PG_NOACC 0 60 #define PG_KW 0x10000000 61 #define PG_KR 0x18000000 62 #define PG_UW 0x20000000 63 #define PG_URKW 0x70000000 64 #define PG_URKR 0x78000000
  • 38.
    処理:pageout() • sys/vm_page.c +696 696loop: 705 (void) splbio(); 706 if (bclnlist != NULL) { 707 (void) spl0(); 708 cleanup(); 709 goto loop; 710 } 711 sleep((caddr_t)&proc[2], PSWP+1); 712 (void) spl0(); 713 count = 0; 714 pushes = 0; 715 while (nscan < desscan && freemem < lotsfree) { 720 if (checkpage(fronthand, FRONT)) 721 count = 0; 722 if (checkpage(backhand, BACK)) 723 count = 0; 724 cnt.v_scan++; 725 nscan++; 726 if (++fronthand >= maxhand) { 727 fronthand = 0; 728 cnt.v_rev++; 729 if (count > 2) { 735 goto loop; 736 } 737 count++; 738 } 739 if (++backhand >= maxhand) 740 backhand = 0; 741 } 742 goto loop; proc[2]はpager,メモリが不足すると wakeupされる Fronthand.backhandを++しながら一 定のpageをスキャンする fronthand backhand maxhand/0
  • 39.
    cmap[hand]がcheckの対象 処理:checkpage() • sys/vm_page.c +774 774c = &cmap[hand]; 775 if (c->c_lock || c->c_free) 776 return (0); 777 switch (c->c_type) { 779 case CSYS: 780 return (0); 782 case CTEXT: 783 xp = &text[c->c_ndx]; 784 rp = xp->x_caddr; 785 v = tptov(rp, c->c_page); 786 pte = tptopte(rp, c->c_page); 787 break; 789 case CDATA: 790 case CSTACK: 791 rp = &proc[c->c_ndx]; 792 while (rp->p_flag & SNOVM) 793 rp = rp->p_xlink; 794 xp = rp->p_textp; 795 if (c->c_type == CDATA) { 796 v = dptov(rp, c->c_page); 797 pte = dptopte(rp, c->c_page); 798 } else { 799 v = sptov(rp, c->c_page); 800 pte = sptopte(rp, c->c_page); 801 } 802 break; 803 } cmapのc_typeに用途が記録 実メモリcmap[hand]が参照している pteを特定
  • 40.
    プロセス空間と物理メモリの関連 cmap[] 物理メモリproc [] c_ndx c_ndx p_tsize p_p0br c_page cmap[n] proc[m] Userstack User Text User Data 0x4000.000 0x0000.000 0x8000.000 P0 P1 #define dptov(p, i) ((unsigned)(stoc(ctos((p)->p_tsize)) + (i))) #define dptopte(p, i) ((p)->p_p0br + ((p)->p_tsize + (i))) pte[]
  • 41.
    処理:checkpage() • sys/vm_page.c +813 813if (pte->pg_v) { 814 if (whichhand == BACK) 815 return(0); 816 pte->pg_v = 0; 817 if (anycl(pte, pg_m)) 818 pte->pg_m = 1; 819 distcl(pte); 820 if (c->c_type == CTEXT) 821 distpte(xp, (unsigned)vtotp(rp, v), pte); 822 if ((rp->p_flag & (SSEQL|SUANOM)) == 0 && 823 rp->p_rssize <= rp->p_maxrss) 824 return (0); 825 }
  • 42.
    処理:checkpage() • sys/vm_page.c +850 850if (dirtycl(pte)) { 856 if (rp->p_flag & (SLOCK|SWEXIT)) 857 return (0); 858 /* 859 * Limit pushes to avoid saturating 860 * pageout device. 861 */ 862 if (pushes > maxpgio / RATETOSCHEDPAGING) 863 return (0); 864 pushes++; 882 loop2: 883 (void) splbio(); 884 if (bclnlist != NULL) { 885 (void) spl0(); 886 cleanup(); 887 goto loop2; 888 } 889 if (bswlist.av_forw == NULL) { 890 bswlist.b_flags |= B_WANTED; 891 sleep((caddr_t)&proc[2], PSWP+2); 892 (void) spl0(); 900 goto top; 901 } 902 (void) spl0(); 904 MLOCK(c); 905 uaccess(rp, Pushmap, &pushutl); 909 pte->pg_m = 0; 910 distcl(pte); 911 if (c->c_type == CTEXT) { 912 xp->x_poip++; 913 distpte(xp, (unsigned)vtotp(rp, v), pte); 914 } else 915 rp->p_poip++; 916 v = kluster(rp, v, pte, B_WRITE, &klsize, klout, (daddr_t)0); 917 if (klsize == 0) 918 panic("pageout klsize"); 919 daddr = vtod(rp, v, &pushutl.u_dmap, &pushutl.u_smap); 920 (void)swap(rp, daddr, ptob(v), klsize * ctob(CLSIZE), 921 B_WRITE, B_DIRTY, swapdev, pte->pg_pfnum); 929 return (1); /* well, it'll be free soon */ 930 931 }
  • 43.
    アドレス変換例外 • machine/trap.c 58 trap(sp,type, code, pc, psl) 59 int sp, type; 60 unsigned code; 61 int pc, psl; 73 switch (type) { 75 default: 76 printf("trap type %d, code = %x, pc = %x¥n", type, code, pc); 77 type &= ~USER; 78 if ((unsigned)type < TRAP_TYPES) 79 panic(trap_type[type]); 80 panic("trap"); 82 case T_PROTFLT+USER: /* protection fault */ 83 i = SIGBUS; 84 break; 119 120 case T_PAGEFLT: /* allow page faults in kernel mode */ 121 case T_PAGEFLT+USER: /* page fault */ 122 i = u.u_error; 123 pagein(code, 0); 124 u.u_error = i; 125 if (type == T_PAGEFLT) 126 return; 127 goto out;
  • 44.
    処理:pagein() • sys/vm_page.c 68 pagein(virtaddr,dlyu) 100 vsave = v = clbase(btop(virtaddr)); 101 p = u.u_procp; 108 pte = vtopte(p, v); 198 bnswap = bncache = bn = vtod(p, v, &u.u_dmap, &u.u_smap); 199 dev = swapdev; 219 opte = *pte; 311 pte->pg_prot = opte.pg_prot; 314 distcl(pte); 377 /* 378 * Fill from swap area. Try to find adjacent 379 * pages to bring in also. 380 */ 381 v = kluster(p, v, pte, B_READ, &klsize, 382 (type == CTEXT) ? kltxt : 383 ((p->p_flag & SSEQL) ? klseql : klin), bn); 384 splx(sk); 385 /* THIS COULD BE COMPUTED INCREMENTALLY... */ 386 bncache = bn = vtod(p, v, &u.u_dmap, &u.u_smap); 387 } 388 389 distcl(pte); 390 swerror = swap(p, bn, ptob(v), klsize * ctob(CLSIZE), 391 B_READ, B_PGIN, dev, 0); !NOTICE!
  • 45.
    第三世代UNIX • Mach由来の仮想記憶に置き換え – 仮想記憶は •f(vnode, offset) → (p, vaddr) • f(p, vaddr) → (vnode,offset) – 広範囲に影響 • 共用テキスト • 共有メモリ • バッファキャッシュ • Demand loading • ForkのCopy On Write化 • Linux,Solaris,BSDで実装は異なるが、考え方は同じ