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

45
UNIX V6 セミナー (4) @magoroku15 2013/5/11

Upload: magoroku-yamamoto

Post on 31-May-2015

1.387 views

Category:

Documents


0 download

TRANSCRIPT

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

UNIX V6 セミナー (4)

@magoroku15

2013/5/11

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

今日の内容

• 過去:UNIX v6, 未来:4.4BSDとの関連

• 仮想記憶の空間構成

• スワッピングとページング

• 4.3BSDを例にした仮想記憶管理の解析

• 参考資料 – Freebsd-53-kernel-mm.pptx 七誌さん

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

過去:UNIX V6, 未来:4.4BSDとの関連

4.3BSD

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

カーネルのメモリ構成

※アドレスは上を0としたため、本とは上下反転

カーネル

ユーザー

0

4GB

1. 常駐型 FreeBSDなど

カーネル ユーザー

2. 切替型 UNIX V6など

http://sdrv.ms/160BJhK より

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

常駐型

カーネル

プロセスA

0

4GB

永続マップ カーネル

プロセスB

• カーネルが同じアドレスに常駐する

タスクスイッチで入替

http://sdrv.ms/160BJhK より

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

切替型

0

4GB

カーネル プロセスA

• 広いメモリ空間を使うことができる

プロセスB

http://sdrv.ms/160BJhK より

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

データの受け渡し

カーネル

ユーザー

0

4GB

1. 常駐型 直接参照(高速)

2. 切替型 特殊命令でコピー(遅い)

カーネル ユーザー

※カーネルは自由にユーザーのメモリを読めるが、逆は不可 http://sdrv.ms/160BJhK より

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

メモリ管理から見た4.3BSDの特徴

• UNIX v{6|7}の空間を切り替え型から常駐型に変更 • On demand paging

– clock algorithm • One handからTwo handへの変更

• 共有メモリはtextのみ – COW, shm, 動的なbufなどは存在しない

• 限定的なカーネルメモリアロケータ – mbufのみ

• VAX-11依存の実装 – PTEにOSの管理情報を置く – 参照ビットのエミュレーション

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

4.3BSDを理解する意味

• UNIXの系譜では第2世代の最後 – 第一世代 UNIX v{6|7} 切り替え型

– 第二世代 UNIX 32v~4.3BSD 常駐型

– 第三世代 Mach, 4.4BSD他 +広義の単一レベル記憶 • 仮想空間にvnode,offsetで表現可能なファイルをマップ可能になる

• 次の事項の理解に有用 – MMUの仕組み

– ページングの原理と実装

– 実メモリ管理

• UNIX v{6|7}の構成の変化は少なく連続性がある – ファイル構成・関数構成

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

仮想記憶の空間構成

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

空間の構成

• 単一仮想空間

–一枚の空間を仮想化する

–一枚の空間に複数のプロセスが同居

– メモリの拡張が主な目的

• 多重仮想空間

–複数の空間を仮想化する

–一枚の空間に1個のプロセスを配置

–システムの保護

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

空間構成 多重仮想空間

単一仮想空間

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

多重仮想空間の管理構造

ユーザ

物理メモリ管理構造

仮想-物理アドレス変換表

カーネル

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

アドレス変換機構

• アドレスの変換単位はページ – 数Kbyte程度

– Aligned

• アドレスの変換表をOSが用意してCPU(MMU)に通知

• MMUが仮想アドレスを実アドレスに変換

変換表

CR

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

アドレス変換表

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

アドレスと変換表の関係

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

2レベル変換表

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

仮想空間の利点

• 複数の独立したアドレス空間

– アドレス空間の間でメモリの書き換え・参照ができない

– プログラムAのバグがプログラムBに影響を与えない

– プログラムAのメモリをプログラムBから参照できない

• 全てのプログラムが同じアドレスを利用可能

– リロケータブルである必要がない

– コンパイラ・リンカの負担が少ない

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

スワッピングとページング

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

スワッピング

• スワップアウト – 最も優先度の低いプログラムを選択し – プログラムをスケジュールの対象から外す – プログラムのメモリ全体をスワップデバイスに退避(write)

• スワップイン – 実行するプロセスがスワップアウトさせていたら – メモリを確保-不足したら他のプロセスをスワップアウト

– スワップデバイスに退避してあるメモリイメージをメモリに復元(read)

– プログラムをスケジュールの対象に含める

• スワッピングとページングは明確に区別せずに使われる場合があるので注意

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

スワッピングの特徴

• プログラム全体を退避・復元

–アドレス空間の拡張に伴ってI/O量が増加

–大きなコストを払ってスワップインしても、その後の挙動は予想できない

• メモリ・フラグメンテーションの解消手段

– UNIX v6等の実装

• ページングと比較してハードウェアの負担が少ない

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

ページング

• ページアウト 1. メモリが不足 2. 最近使われていない物理メモリ(ページ)を特定

3. 物理メモリが仮想メモリとして利用されていたら変換対象から外す

4. 物理メモリをページングデバイスに退避

• ページイン 1. 割り当て済の仮想メモリをプログラムが参照 2. アドレス変換例外で割り込みが発生しOSに制御が移る 3. OSが該当プロセス+アドレスから退避済の物理メモリ(ページ)を特定する

4. 物理メモリを読み込んで仮想メモリから変換可能とする 5. 割り込みから復帰

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

ページングの特徴

• 一般的な運用では – 仮想空間の総量 > 物理メモリ – 物理メモリの奪い合い – メモリ参照に局所性が有る場合

• ゆっくり奪い合う→変換例外とその対応のコストは無視できる

– メモリ参照に局所性が無い場合 • はげしく奪い合う→変換例外とその対応コストが無視できない

• 局所的な参照を前提として使われていないメモリの特定が必要 – 最近利用されていないメモリは将来も利用されない可能性が高い

– どうやって?

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

LRU - Least Recently Used

• 「最近使われていないメモリは、将来も使われない可能性が高い」事を前提とする

• メモリの参照頻度を記録して、最近使われていないメモリを予想する

–近年のCPUは参照の有無をアドレス変換表にHWが記録する

• X86, ARMなど (除くVAX-11)

• 多くは1bit(参照の有無)のみを記録

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

仮想記憶の構成

4.3BSDを例に

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

解析の対象

• 4.3BSD

– 1986年、カルフォルニア大学バークレー校で開発・配布された近代UNIX

–仮想記憶・TCP/IP・拡張ファイルシステムが特徴

– ソースの入手にはAT&T UNIXのライセンスが必要

–今回は以下を利用http://www.tamacom.com/tour-j.html

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

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

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

VAX-11の仮想記憶

• 512byte/1ページ 9bit

• 32bitのアドレス幅上位2bitがリージョン – P0=00,P1=01,S=10

32bit

Page offset 9bit

Segmant 2bit

Virtual Page Number 21bit

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

セグメントとページテーブル

• 各セグメントはPTEの配列=ページテーブルとして表現 –セグメントベースレジスタ:SEGBR

–セグメントリミットレジスタ:SEGLR

• 各リージョンは2^21個のページを持つ – 1リージョン8MBのページテーブルが必要

– P0,P1,Sで24Mbyte/プロセス必要

– P0,P1のページテーブルはSのカーネル仮想に配置

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

セグメント用のレジスタ

• 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

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

セグメントレジスタの設定

• 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にアドレス変換レジスタの内容を持っていたのと同じ

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

実メモリ(ページ)管理

4.3BSDを例に

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

構造: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 };

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

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を確保

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

ページの割り当て: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 }

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

ページング

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

構造: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 };

pfnum V 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

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

処理: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

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

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を特定

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

プロセス空間と物理メモリの関連 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[]

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

処理: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 }

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

処理: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 }

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

アドレス変換例外

• 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;

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

処理: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!

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

第三世代UNIX

• Mach由来の仮想記憶に置き換え

– 仮想記憶は • f(vnode, offset) → (p, vaddr)

• f(p, vaddr) → (vnode,offset)

– 広範囲に影響 • 共用テキスト

• 共有メモリ

• バッファキャッシュ

• Demand loading

• ForkのCopy On Write化

• Linux,Solaris,BSDで実装は異なるが、考え方は同じ