Más contenido relacionado La actualidad más candente (20) Similar a 2章 Linuxカーネル - メモリ管理1 (20) 2章 Linuxカーネル - メモリ管理11. 2章 Linuxカーネル - メモリ管理1
mao
Web >http://www.pridact.com
Twitter >https://twitter.com/rivarten
Blog >http://rivartender.blog.fc2.com
Mail >official@pridact.com
11. 1.アドレス変換機能 - x86におけるセグメンテーション(2)
・セグメントセレクタ
・セグメントディスクリプタテーブル
・GDT(Global Descriptor Table)
システムに1つのみ存在するテーブル。
・LDT(Local Descriptor Table)
各プロセス固有のテーブル。
プロセスが任意で持つ。
bit 内容
15~3 インデックス値。
GDTかLDT内にある、対応するセグメントディスクリプタを示す。
2 TI(Table Indicator)
0:GDTにある。 1:LDTにある。
1,0 RPL(Requestor Privilege Level)/リクエスタ特権レベル
Linuxカーネルでは、CPL(Current Privilege Level)/現行特権レ
ベルとして扱っている。
0:カーネル 3:ユーザ
1,2:仮想化マシン
12. 1.アドレス変換機能 - x86におけるセグメンテーション(3)
・セグメントディスクリプタのフィールド内容
フィールド名 内容
ベース セグメント先頭のリニアアドレス
G Granularity/粒度。セグメント長の単位。
0:byte 1:page
リミット セグメント終端のメモリセルのオフセット=セグメント長。
G=0: 1byte~1MB G=1:4KB~4GB
S システムフラグ
0:システムセグメント。重要なデータを置く。
1:通常のコードセグメント、データセグメント。
タイプ セグメントの種類、アクセス権。
DPL Descriptor Privilege Level
セグメントへのアクセスに必要な特権レベル
0:カーネル 3:ユーザ
P Present
セグメント存在フラグ。メインメモリ上に存在するかどうか。
0:存在しない 1:存在する
(Linuxではセグメント全体をスワップアウトする事はない⇒常に1)
D/B デフォルトのオペレーションサイズ/デフォルトのスタックポインタサイズ
0:16bit 1:32bit
AVL 使用可能ビット。OS用。Linuxでは不使用。
15. 1.アドレス変換機能 - x86におけるセグメンテーション(6)
・コードセグメントディスクリプタ
・GDT or LDT内にある。
・データセグメントを表す。
・S=1(非システムセグメント)
・スタックセグメントは、汎用データセグメントの1つ。
bit 内容
63~56 ベース(31~24bit)
55 G
54 (D/)B
53 0
52 AVL
51~48 リミット(19~16bit)
47 1
46~45 DPL
44 S=1
43~40 タイプ
39~32 ベース(23~16bit)
31~16 ベース(15~0bit)
15~0 リミット(15~0bit)
25. 1.アドレス変換機能 - Linuxにおけるセグメンテーション(2)
・Linuxにおける主なセグメントの種類(x86)
1.ユーザコードセグメント __USER_CS
2.ユーザデータセグメント __USER_DS
3.カーネルコードセグメント __KERNEL_CS
4.カーネルデータセグメント __KERNEL_DS
・Linuxにおける主なセグメントの種類(x86_64)
1.32bitユーザコードセグメント __USER32_CS
2.32bitユーザデータセグメント __USER32_DS
3.64bitユーザーコードセグメント __USER_CS
4.64bitユーザーデータセグメント __USER_DS
5.32bitカーネルコードセグメント __KERNEL32_CS
6.64bitカーネルコードセグメント __KERNEL_CS
7.64bitカーネルデータセグメント __KERNEL_DS
28. 1.アドレス変換機能 - Linuxにおけるセグメンテーション(5)
・LinuxにおけるGDT(1) x86 version
セグメントセレクタ 内容 セグメントセレクタ 内容
[0]0x00 nullセグメント [16]0x80 TSS descriptor
[1]0x08 reserved(null seg) [17]0x88 LDT descriptor
[2]0x10 reserved(BOOT_CS) [18]0x90 PnP BIOS 32bit code
[3]0x18 reserved(BOOT_DS) [19]0x98 PnP BIOS 16bit code
[4]0x20 unused(BOOT_TSS) [20]0xA0 PnP BIOS data
[5]0x28 unused [21]0xA8 PnP BIOS 16bit ts1
[6]0x30 TLS entry 1(glibc) [22]0xB0 PnP BIOS 16bit ts2
[7]0x38 TLS entry 2(Wine) [23]0xB8 APM CS 32bit BIOS code
[8]0x40 TLS entry 3 [24]0xC0 APM CS 32bit BIOS code
[9]0x48 reserved [25]0xC8 APM DS data
[10]0x50 reserved [26]0xD0 ESPFIX small SS
[11]0x58 reserved [27]0xD8 per-cpu
[12]0x60 __KERNEL_CS [28]0xE0 stack_canary-20
[13]0x68 __KERNEL_DS [29]0xE8 unused
[14]0x73(70+3) __USER_CS [30]0xF0 unused
[15]0x7B(78+3) __USER_DS [31]0xF8 double-fault TSS
29. 1.アドレス変換機能 - Linuxにおけるセグメンテーション(6)
・LinuxにおけるGDT(2)
1.TSS(Task State Segment)
・システムのプロセッサ毎に用意しているセグメントディスクリプタ。
・TSSのリニアアドレス空間は、__KERNEL_DSのリニアアドレス空間の一部にマッピング。
・タイプ = 9 or 11(32bit TSSを有効化)
2.LDT(Local Descriptor Table)
・標準初期設定のLDTのセグメント。
・通常、全てのプロセスがこのセグメントを共有。
3.TLS(Thread-Local Storage)
・マルチスレッドアプリケーションにおける、スレッド固有データを保持するセグメント。
set_thread_area()システムコール:確保
get_thread_area()システムコール:解放
31. 1.アドレス変換機能 - Linuxにおけるセグメンテーション(8)
・__USER32_CS
フィールド名 値
ベース 0x00000000
G 1
リミット 0xFFFFF
S 1
タイプ 5
DPL 3
D 1
L 0
P 1
・__USER32_DS
__USER_DS
フィールド名 値
ベース 0x00000000
G 1
リミット 0xFFFFF
S 1
タイプ 1
DPL 3
D 1
L 0
P 1
Linuxにおける主なセグメントの種類(x86_64)(1)
・__USER_CS
フィールド名1 値
ベース 0x00000000
G 1
リミット 0xFFFFF
S 1
タイプ 5
DPL 3
D 0
L 1
P 1
33. 1.アドレス変換機能 - Linuxにおけるセグメンテーション(10)
・LinuxにおけるGDT x86_64 version
セグメントセレクタ 内容 セグメントセレクタ 内容
[0]0x00 nullセグメント [8]0x40 TSS
[1]0x08 __KERNEL32_CS [9]0x48 unused
[2]0x10 __KERNEL_CS [10]0x50 LDT
[3]0x18 __KERNEL_DS [11]0x58 unused
[4]0x23(20+3) __USER32_CS [12]0x63(60+3) TLS 1(GS_TLS_SEL)
[5]0x2B(28+3) __USER_DS
__USER32_DS
[13]0x6B(68+3) TLS 2(FS_TLS_SEL)
[6]0x33(30+3) __USER_CS [14]0x70 TLS 3
[7]0x38 unused [15]0x7B(78+3) __PER_CPU_SEG
36. 1.アドレス変換機能 – x86におけるページング(1) - 概要
・ページング機構
仮想的に連続したメモリ空間や、
他のプログラムから独立したメモリ空間を提供。
・ページフレーム
リニアアドレスの分割枠
・ページ
ページフレーム内に配置する実際のデータ
・ページテーブル(アドレス変換テーブル)
リニアアドレスを物理アドレスにマッピングするデータ構造
cr0制御レジスタのPGフラグ=1でページング有効化。
PGフラグ=0でリニアアドレス=物理アドレス。
38. 1.アドレス変換機能 - x86におけるページング(3)
・各テーブルエントリのフィールド(1)
フィールド 内容
G グローバル
ページテーブルエントリの場合のみ使用。
頻繁に使用するページがTLBから追い出されるのを防ぐ事が出来るフラグ。
(Pentium Pro以降)
cr4制御レジスタのPGEフラグ=1で有効化。
0:TLBからクリアする 1:TLBからクリアしない
PS ページサイズ
ページディレクトリエントリの場合のみ使用。
0:4KB 1:2MB or 4MB
D ダーティ
ページテーブルエントリの場合のみ使用。
ページング回路は、ページフレームに対する書き込み処理が行われる度に、
Dフラグを1にする。
Dフラグを0にするのはOS。
0:ページテーブル/ページは書き込まれていない
1:ページテーブル/ページは書き込まれた
メモリの内容をディスクに書き戻す必要があるかの判定に使用
※TLBはキャッシュ的存在。後述。
39. 1.アドレス変換機能 - x86におけるページング(4)
・各テーブルエントリのフィールド(2)
フィールド 内容
A アクセス済み
ページング回路は、対応するページフレームにアクセスする度に、Aフラグを1にする。
Aフラグを0にするのはOS。
0:ページテーブル/ページはアクセスされていない
1:ページテーブル/ページはアクセス済み
あるタイミングでクリアし、その後全エントリのAフラグをチェックすると、最近アクセスさ
れたかどうか判定できる。
スワップデバイスに退避するページを選択するのに利用。
PCD ページレベルキャッシュディスエーブル
0:キャッシング可能 1:キャッシング禁止
PWT ページレベルライトスルー
0:ライトバックキャッシング可能
1:ライトスルーキャッシング可能
U/S ユーザ/スーパーバイザ
0:スーパーバイザ 1:ユーザ
R/W アクセス権
0:R 読み取り専用 1:RW 読み書き可能
P 存在
0:ページテーブル/ページが存在しない 1:ページテーブル/ページが存在する
0⇒ページング回路は、変換失敗したリニアアドレスをcr2制御レジスタに保存。
その後、14番の例外(ページフォールト例外)を発生させる。
40. 1.アドレス変換機能 - x86におけるページング(5)
ページディレクトリエントリPDE
index bit数 内容
31~12 20 ページテーブルbase
11~9 3 -(AVAIL未使用)
8 1 -(G未使用)
7 1 PS=0
6 1 -(D未使用)
5 1 A
4 1 PCD
3 1 PWT
2 1 U/S
1 1 R/W
0 1 P
ページテーブルエントリPTE
index bit数 内容
31~12 20 ページフレームbase
11~9 3 -(AVAIL未使用)
8 1 G=0
7 1 -(PS未使用)
6 1 D
5 1 A
4 1 PCD
3 1 PWT
2 1 U/S
1 1 R/W
0 1 P
42. 1.アドレス変換機能 – x86におけるページング(7)
・物理アドレス拡張PAE(Physical Address Extension)
・OS1GB問題
Linuxのリニアアドレス4GBの内約
ユーザーモードプロセス:3GB OS:1GB
OSは1GBでやりくりする必要あり。巨大サーバでは足りない
・対策(Pentium Pro以降)
アドレスピン32本→36本に拡張⇒物理アドレス空間4GB→64GB利用可能
・リニアアドレスは32bitのまま
・ページテーブルエントリのページフレームbase 20bit→24bit
64GB RAMを2^24個のページフレームに分割
・ページテーブルエントリのサイズ32bit→64bit
ページフレームbase 24bit + オフセット 12bit = 36bitでオーバーの為。
・ページディレクトリポインタテーブルPDPT(Page Directory Pointer Table)導入
各エントリ64bitの4エントリ。ページディレクトリの上階層に置く。cr3制御レジスタでbase指定
※ページテーブル操作が可能なのはOSのみ
⇒OSは物理アドレスを最大64GB利用可能。
ユーザーモードプロセスは4GBのまま。
※PAE有効kernelは無効kernelを使用した場合よりも、最大で50%の性能低下。
PAE有効kernelでは、ページテーブル構造の階層が1つ多い為、
TLBがミスヒットした場合のペナルティーが大きい。
メモリを大量に管理している為、TLBヒット率があまり高くない。
43. 1.アドレス変換機能 - x86におけるページング(8)
index bit数 内容
31~30 2 PDPT offset
29~21 9 PDE offset
20~12 9 PTE offset
11~0 12 Page offset
index bit数 内容
31~30 2 PDPT offset
29~21 9 PDE offset
20~0 20 Page offset
・PAE有効時の32bitリニアアドレスの内約
・PDEのPSフラグ=0(4KBページ)
cr3制御レジスタ:PDPT base
・PDEのPSフラグ=1(2MBページ)
cr3制御レジスタ:PDPT base
45. 1.アドレス変換機能 - x86_64におけるページング(1)
アーキテクチャ 有効アドレス
bit数
ページング階層数 リニアアドレス分割方法
alpha 43 3 10 + 10 + 10 + 13
ia64 39 3 11 + 11 + 11 + 14
ppc64 41 3 10 + 10 + 9 + 12
sh64 41 3 10 + 10 + 9 + 12
x86_64 48 4 9 + 9 + 9 + 9 + 12
・64bitアーキテクチャにおけるページング
47. 1.アドレス変換機能 - x86_64におけるページング(3)
PML4 Entry
index bit数 内容
63 1 XD
62~52 11 -(AVAIL未使用)
51~40 12 -(予約済み,
PDPT base未使用,0)
39~12 28 PDPT base
11~9 3 -(AVAIL未使用)
8 1 -(G未使用)
7 1 -(予約済み,PS=0)
6 1 -(D未使用)
5 1 A
4 1 PCD
3 1 PWT
2 1 U/S
1 1 R/W
0 1 P
PDPT Entry
・64bitモードのページング(2)
index bit数 内容
63 1 XD
62~52 11 -(AVAIL未使用)
51~40 12 -(予約済み,PD base,0)
39~12 28 PD base
11~9 3 -(AVAIL未使用)
8 1 -(G未使用)
7 1 -(予約済み,PS=0)
0:4KB 1:1GB
6 1 -(D未使用)
5 1 A
4 1 PCD
3 1 PWT
2 1 U/S
1 1 R/W
0 1 P
48. 1.アドレス変換機能 - x86_64におけるページング(4)
PD Entry
index bit数 内容
63 1 XD
62~52 11 -(AVAIL未使用)
51~40 12 -(予約済み,PT base,0)
39~12 28 PT base
11~9 3 -(AVAIL未使用)
8 1 -(G未使用)
7 1 PS
0:4KB 1:2MB
6 1 -(D未使用)
5 1 A
4 1 PCD
3 1 PWT
2 1 U/S
1 1 R/W
0 1 P
PT Entry
・64bitモードのページング(3)
index bit数 内容
63 1 XD
62~52 11 -(AVAIL未使用)
51~40 12 -(予約済み,Page base,0)
39~12 28 Page base
11~9 3 -(AVAIL未使用)
8 1 G
7 1 PAT
6 1 D
5 1 A
4 1 PCD
3 1 PWT
2 1 U/S
1 1 R/W
0 1 P
49. 1.アドレス変換機能 - x86_64におけるページング(5)
・64bitモードのページング(4)
ページサイズが3通り:4KB,2MB,1GB
4KB
・フラグ
PDPE:PS=0,PDE:PS=0
・変換パス
PML4E→PDPE→PDE→PTE→Page
・リニアアドレス分割
9,9,9,9,12
2MB
・フラグ
PDPE:PS=0,PDE:PS=1
・変換パス
PML4E→PDPE→PDE→Page
・リニアアドレス分割
9,9,9,0,21
1GB
・フラグ
PDPE:PS=1
・変換パス
PML4E→PDPE→Page
・リニアアドレス分割
9,9,0,0,30
52. 1.アドレス変換機能 – Linuxにおけるページング(2)
・PAE無効 & 32bitアーキテクチャ
・2階層 ⇒ PUD,PMDのbit数=0
・Linuxとx86のページ変換テーブル対応
PGD = x86 PD
PUD = なし
PMD = なし
PTE = x86 PT
・PAE有効 & 32bitアーキテクチャ
・3階層 ⇒ PUDのbit数=0
・Linuxとx86のページ変換テーブル対応
PGD = x86 PDP
PUD = なし
PMD = x86 PD
PTE = x86 PT
55. 1.アドレス変換機能 - Linuxにおけるページング(5)*
・ページテーブル操作(1) マクロ(1)
マクロ 内容
PAGE_SHIFT オフセットフィールドのビット長。x86:12。
PAGE_SIZEマクロがページ長を返す為に使用。
PAGE_SIZE ページ長を返す
PAGE_MASK 0xFFFFF000を返し、オフセットフィールドのビットをマスクする時に使用。
PMD_SHIFT リニアアドレスのオフセットフィールドとテーブルフィールドのビット長の合計。
PMDの1エントリがマッピングするビット長。
PAE無効:22 PAE有効:21
PMD_SIZE PMDの1エントリがマッピングできる領域の大きさ。
PAE無効:2^22(4MB) PAE有効:2^21(2MB)
PMD_MASK オフセットフィールドとテーブルフィールドの全ビットをマスクする時に使用。
56. 1.アドレス変換機能 - Linuxにおけるページング(6)*
・ページテーブル操作(2) マクロ(2)
[ver4.2 arch/x86/include/asm/pgtable-2level_types.h]
[ver4.2 arch/x86/include/asm/pgtable-3level_types.h]
マクロ 内容
PUD_SHIFT PUDの1エントリがマッピングできる領域サイズのビット合計。
x86:PUD_SHIFT=PMD_SHIFT
PUD_SIZE PUDの1エントリがマッピングできる領域のサイズ。
x86:4MB or 2MB(PMDに依存)
PUD_MASK オフセット、テーブル、ミドルディレクトリの全ビットをマスクする時に利用。
PGDIR_SHIFT PGDの1エントリがマッピングできる領域サイズのビット合計。
x86:PGDIR_SHIFT=PMD_SHIFT,PUD_SHIFT
PAE無効:22 PAE有効:30
PGDIR_SIZE PGDの1エントリがマッピングできる領域のサイズ。
PAE無効:4MB PAE有効:1GB
PGDIR_MASK オフセット、テーブル、ミドルディレクトリ、アッパーディレクトリの
全ビットをマスクする時に利用。
0xC0000000
PTRS_PER_PTE
PTRS_PER_PMD
PTRS_PER_PUD
PTRS_PER_PGD
各エントリ数を計算。
PAE無効:1024,1,1,1024 (2段)
PAE有効:512,512,1,4 (3段)
57. 1.アドレス変換機能 - Linuxにおけるページング(7)*
・ページテーブル操作(3) ページ変換テーブルのエントリ
・型変換マクロ
符号なし整数→エントリの型
__pte,__pmd,__pud,__pgd,__pgprot
エントリの型→符号なし整数
pte_val,pmd_val,pud_val,pgd_val,pgprot_val
・指定値書き込み
set_pte,set_pmd,set_pud,set_pgd,set_pte_atomic
型 内容
pgd_t PGDエントリ
pud_t PUDエントリ
pmd_t PMDエントリ
pte_t PTエントリ
pgprot_t エントリの保護フラグ
58. 1.アドレス変換機能 - Linuxにおけるページング(8)*
・ページテーブル操作(4) ページ割り当て関数(1) PGD,PUD
マクロ 内容
pgd_alloc PGDの作成
pgd_free PGDの解放
pgd_offset リニアアドレスに対応するPGDエントリのアドレスを取得
pgd_none PGDエントリが空かどうか判定
pgd_bad PGDエントリが不正かどうか判定
pgd_clear PGDエントリをクリアする
pud_alloc_one PUDの作成
pud_free PUDの解放
pud_offset リニアアドレスに対応するPMDエントリのアドレスを取得
pud_none PUDエントリが空かどうか判定
pud_bad PUDエントリが不正かどうか判定
pud_clear PUDエントリをクリアする
59. 1.アドレス変換機能 - Linuxにおけるページング(9)*
・ページテーブル操作(5) ページ割り当て関数(2) PMD,PTE
マクロ 内容
pmd_alloc PMDの作成
pmd_free PMDの解放
pmd_offset リニアアドレスに対応するPMDエントリのアドレスを取得
pmd_none PMDエントリが空かどうか判定
pmd_bad PMDエントリが不正かどうか判定
pmd_clear PMDエントリをクリアする
pte_alloc_one PTEの作成
pte_alloc_one_kernel PTEの作成(カーネル空間用)
pte_free PTEの解放
pte_free_kernel PTEの解放(カーネル空間用)
pte_offset_map リニアアドレスに対応するPTエントリのアドレス取得
pte_offset_map_nested 同上(一度に2つのPTを参照する際に使用)
pte_offset_kernel リニアアドレスに対応するPTエントリのアドレス取得(マスターカーネルPGD)
pte_unmap pte_offset_mapを使用した際、使用し終わったら呼ぶ
pte_unmap_nested pte_offset_map_nestedを使用した際、使用し終わったら呼ぶ
pte_none PTEが空かどうか判定
pte_present 対応する実ページが存在するかどうか判定
62. 1.アドレス変換機能 - Linuxにおけるページング(12)*
・ページテーブル操作(8) ページフラグ変更関数(2) PTE
マクロ 内容
pte_modify(p,v) PTエントリpの全アクセス権の値を指定値vにする
ptep_set_wprotect pte_wrprotectと同様だが、PTEへのポインタで指定
ptep_set_access_flags D=1
⇒ページのアクセス権を指定値に設定し、
flush_tlb_page()関数を呼び出す
ptep_mkdirty pte_mkdirtyと同様だが、PTEへのポインタで指定
ptep_test_and_clear_dirty pte_mkcleanと同様だが、PTEへのポインタで指定し、
変更前のフラグを返す。
ptep_test_and_clear_young pte_mkoldと同様だが、PTEへのポインタで指定し、
変更前のフラグを返す。
63. 1.アドレス変換機能 - Linuxにおけるページング(13)*
・ページテーブル操作(9) PTEエントリ操作関数/マクロ(1)
マクロ 内容
pgd_index(addr) リニアアドレスaddrと対応するPGDエントリのインデックスを返す
pgd_offset(mm,addr) メモリディスクリプタmmとリニアアドレスaddrを受け取り、
addrに対応するPGDエントリのリニアアドレスを返す。
PGDはmm内のポインタが指している。
pgd_offset_k(addr) リニアアドレスaddrに対応するマスターカーネルPGDのリニアアドレスを返す
pgd_page(pgd) PGDエントリpgdが指すPUDのあるページフレームを見つけ、
そのページフレームを管理するページディスクリプタのアドレスを返す。
2階層/3階層ページングシステム ⇒ pgd_page = pud_page
pud_offset(pgd,addr) PGDエントリpgdとリニアアドレスaddrを受け取り、
addrに対応するPUDのリニアアドレスを返す。
2階層/3階層ページングシステム ⇒ pgdを返す
pud_page(pud) PUDエントリpudが指すPMDのリニアアドレスを返す。
2階層ページングシステム ⇒ pud_page = pmd__page
pmd_index(addr) リニアアドレスaddrと対応するPMDエントリのインデックスを返す
pmd_offset(pud,addr) PUDエントリpudとリニアアドレスaddrを受け取り、
addrに対応するPMDにリニアアドレスを返す。
2階層ページングシステム ⇒ pudを返す
pmd_page(pmd) PMDエントリpmdが指すPTエントリのリニアアドレスを返す。
2階層ページングシステム ⇒ pmdはPGDエントリと同じ
64. 1.アドレス変換機能 - Linuxにおけるページング(14)*
・ページテーブル操作(10) PTEエントリ操作関数/マクロ(2)
マクロ 内容
mk_pte(p,prot) ページディスクリプタpとアクセス権protを引数として受け取り、
PTEを作成
pte_index(addr) リニアアドレスaddrをマッピングしているPTEのインデックスを返す
pte_page(x) PTエントリxが参照しているページディスクリプタのアドレスを返す
pte_to_pgoff(pte) PTエントリの中身から、PTが指しているページを非線形ファイルマッピ
ングしているファイルでのオフセットを求める
pgoff_to_pte(offset) 非線形ファイルマッピングするページ用のPTエントリの値を作成
66. 1.アドレス変換機能 – アドレス変換バッファ(1)
・アドレス変換バッファTLB
(Translation Lookaside Buffer)
・x86には、リニアアドレス変換を高速化する為の
バッファ/キャッシュが存在する。
・リニアアドレスを初めて使用する時は、アドレス変換テーブルを
用いて物理アドレスを算出。
この時、物理アドレスをTLBエントリに記憶させる。
次回同じリニアアドレスを使用する時はTLBエントリにアクセス。
・マルチプロセッサシステムでは、各CPUはローカルTLBを持つ。
各ローカルTLBは同期の必要はない。
・cr3制御レジスタの内容が変わる
⇒ローカルTLBの全エントリ無効化
※使用する変換テーブルが変わり、TLBが古いデータを指す為。
67. 1.アドレス変換機能 – アドレス変換バッファ(2)*
・TLBの制御(1) - アーキテクチャ非依存
・TLBキャッシュの同期は自動では行わない。
・リニアアドレスと物理アドレス間の対応を無効化する処理は、
カーネルが行う。
アーキテクチャ非依存のTLB無効化方法(1)
関数 内容
flush_tlb_all 全TLBエントリ無効化。
Gが設定されているグローバルページ用のTLBエントリも無効化。
カーネルページテーブルエントリを変更した時。
flush_tlb_kernel_range 指定したリニアアドレス範囲の全TLBエントリ無効化。
グローバルページ用のTLBエントリも無効化。
あるアドレス範囲のカーネルページテーブルエントリを変更した時。
flush_tlb カレントプロセスに関連するすべての非グローバルページ用のエント
リ無効化。
プロセス切り替えを実行した時。
68. 1.アドレス変換機能 – アドレス変換バッファ(3)*
・TLBの制御(2) - アーキテクチャ非依存
アーキテクチャ非依存のTLB無効化方法(2)
関数1 内容
flush_tlb_mm 指定したプロセスの指定したリニアアドレス範囲に対応するTLBエン
トリ無効化。
プロセスの一部のリニアアドレス範囲を解放した時。
flush_tlb_range 指定したプロセスの指定した範囲のページテーブルに対応するTLB
エントリ無効化。
プロセス一部のページテーブルを解放した時。
flush_tlb_pgtables 指定したプロセスの指定したアドレスに対応するページテーブルエン
トリのTLBエントリ無効化。
ページフォルトを処理した時。
69. 1.アドレス変換機能 – アドレス変換バッファ(4)*
・TLBの制御(3) - アーキテクチャ依存
・Pentiumの全モデルで、cr3制御レジスタに値が書き込まれたときに、
非府グローバルページに対応するTLBエントリを無効化。
・PentiumPro以降のモデルでは、invlpgアセンブリ言語命令を使用して、
指定したリニアアドレスに対応するTLBエントリを無効化する。
アーキテクチャ依存のTLB無効化方法 – PentiumPro以降のプロセッサ用のTLB無効化マクロ
・x86では、flush_tlb_pgtable()は何もしない。
ページテーブルを親ページテーブルから解放する場合に何もしなくてよい。
・マルチプロセッサ用のTLB無効化方法
あるCPUで実行している関数は、他のCPUにプロセッサ間割り込みを送り、
そのCPUにTLB無効化関数を実行させる。
関数 内容 利用しているメソッド
__flush_tlb() cr3制御レジスタに同じ値を
再設定する
flush_tlb,flush_tlb_mm
flush_tlb_range
__flush_tlb_global() cr4制御レジスタのPGE=0にして
グローバルページを無効にし、
cr3制御レジスタの値を再設定し
て、再度PGE=1にする。
flush_tlb_all,
flush_tlb_kernel_range
__flush_tlb_single(addr) addrを引数として、invlpgアセンブ
リ言語命令を実行。
flush_tlb_range
70. 1.アドレス変換機能 – アドレス変換バッファ(5)*
・TLBの制御(4) - TLB無効化タイミング
・基本的にすべてのプロセス切り替えにおいて、
プロセスが使用するページテーブルを切り替える。
⇒CPUのローカルTLBエントリも無効化する必要があり、
新しいPGDアドレスをcr3制御レジスタに書き込んだ時に、
ハードウェアによって 自動的に行われる。
・カーネルがユーザーモードプロセスにページフレームの割り当てを行い、
割り当てたページフレームの物理アドレスをPTEに書き込む場合、
割り当てたリニアアドレスを参照しているローカルTLBエントリを無効化。
・マルチプロセッサシステムで同じページテーブルを使用しているCPUがあれ
ば、対応するCPUのTLBエントリを無効化実行。
[例外]
・同じページテーブルを使用している通常プロセス間でのプロセス切り替え
(=同一プロセスに属するスレッド間切り替え)
・通常プロセスとカーネルスレッド間でプロセス切り替えを行う場合。
カーネルスレッドは固有のページテーブルを持っていない為、
直前に動作していた通常プロセスのページテーブルをそのまま使用する
71. 1.アドレス変換機能 – アドレス変換バッファ(6)*
・TLBの制御(5) – マルチプロセッサ環境における
無駄なTLB無効化対策(1)
・遅延TLBモード(Lazy TLB Mode)
いくつかのCPUが同じページテーブルを使用していて、TLBを無効化する必要がある場合、
カーネルスレッドを実行しているCPUのTLB無効化を延期させる。
※flush_tlb_all()ではこのモードを使用しない。
・カーネルスレッドは固有のページテーブルを持っていない為、
通常プロセスのページテーブルをそのまま使用している。
カーネルスレッドはユーザーモードのアドレス空間にアクセスしないので、
ユーザーモードのリニアアドレス空間に対応するTLBエントリを無効化する必要は無い。
・TLBエントリ無効化要求が発行されても、遅延TLBモードのCPUはTLBエントリを無効化しない。
カレントプロセスのユーザーモードアドレスのTLBエントリが使えない事を覚えておく。
遅延TLBモードのCPUが、
・違うページテーブルを持つプロセスに切り替わった場合
⇒即ハードウェアが自動的にTLBエントリを無効化し、非遅延TLBモードに戻す。
・直前のカーネルスレッドと同じページテーブルを持つ通常プロセスに切り替わった場合
⇒延期していたTLB無効化処理を行う。
この遅延した無効化処理は、すべての非グローバルなTLBエントリを無効化する。
72. 1.アドレス変換機能 – アドレス変換バッファ(7)*
・TLBの制御(6) – マルチプロセッサ環境における
無駄なTLB無効化対策(2)
・cpu_tlbstate変数
・struct tlb_state構造体をCPU毎に使える様に定義。
宣言(DECLARE_PER_CPU_SHARED_ALIGNEDマクロ)
[ver4.2 arch/x86/include/asm/tlbflush.h:18]
定義(DEFINE_PER_CPU_SHARED_ALIGNEDマクロ)
[ver4.2 arch/x86/mm/init.c:736]
・active_mmメンバ:カレントプロセスのメモリディスクリプタmm_struct構造体
[ver4.2 include/linux/mm_types.h:392]
・メモリディスクリプタのcpu_vm_mask_varメンバ
TLBの無効化を要求するプロセッサ間割り込みを受け付けるCPUのインデックス値。
カレントプロセスのメモリディスクリプタに属している場合のみ有効。
・stateメンバ
TLBSTATE_OK :非遅延TLBモード
TLBSTATE_LAZY :遅延TLBモード
73. 1.アドレス変換機能 – アドレス変換バッファ(8)*
・TLBの制御(7) – マルチプロセッサ環境における
無駄なTLB無効化対策(3)
・遅延TLBモードの利用
1.CPUがカーネルを実行する場合、
・cpu_tlbstate::stateメンバをTLBSTATE_LAZYにする。
・カレントプロセスのメモリディスクリプタのcpu_vm_mask_varメンバに、
遅延TLBモードのCPUを含むシステム上の全CPUインデックスに対応する
全てのビットを1にする。
2.別のCPUが、指定されたページテーブルに関連する全てのCPUのTLBエントリを無効化する
場合、該当するメモリディスクリプタのcpu_vm_mask_varメンバのインデックスが示して
いる全てのCPUに対して、プロセッサ間割り込みを送る。
3.CPUがTLB無効化を要求するプロセッサ間割り込みを受け取り、
カレントプロセスのページテーブルに影響がある事を確認した場合、
・cpu_tlbstate::state = TLBSTATE_LAZY
⇒TLB無効化を行わない
実行しているプロセスのメモリディスクリプタのcpu_vm_mask_varメンバから、
自分のCPUに対応するビットを0にする。
・遅延TLBモードにある限り、TLB無効化関連のプロセッサ間割り込みを受け付けない。
・直前のカーネルスレッドと同じページテーブルを使用するプロセッサに切り替わった場合、
カーネルは__flush_tlb()を実行し、そのCPU上のすべての非グローバルTLBエントリ無効化
79. 1.アドレス変換機能 – 物理メモリレイアウト(5)*
・物理アドレスマップの作成手順(2)
1.カーネル起動処理の初期段階
BIOSを呼び出して、物理メモリの大きさを問い合わせる。
物理アドレス範囲とメモリ種類の一覧を作成。
・BIOS-e820機能を利用(AXレジスタ0xE820時のINT 0x15の動作/機能)
・コールスタック
main()[ver4.2 arch/x86/boot/main.c:135]
→detect_memory()[ver4.2 arch/x86/boot/memory.c:122]
→detect_memory_e820()[ver4.2 arch/x86/boot/memory.c:20]
・boot_params::e820_map構造体配列に格納。
(struct boot_params構造体メンバのstruct e820entry構造体の配列)
・struct boot_params構造体 [ver4.2 arch/x86/include/uapi/asm/bootparam.h:114]
インスタンス [ver4.2 arch/x86/kernel/setup.c:145]
・struct e820entry構造体 [ver4.2 arch/x86/include/uapi/asm/e820.h:58]
struct e820entry {
__u64 addr; /* start of memory segment */
__u64 size; /* size of memory segment */
__u32 type; /* type of memory segment */
} __attribute__((packed));
・type
1:usable,2:reserved,3:ACPI data,4:ACPI NVS(Non Volatile Sleeping,不揮発)
※BIOS機能参考 http://www.ctyme.com/intr/int.htm
80. 1.アドレス変換機能 – 物理メモリレイアウト(6)*
・物理アドレスマップの作成手順(3)
<例>(x86,1.5GBメモリ,実機)のdmesg結果
[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000000e6000-0x00000000000fffff] reserved
[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000005f72fbff] usable
[ 0.000000] BIOS-e820: [mem 0x000000005f72fc00-0x000000005f72ffff] ACPI NVS
[ 0.000000] BIOS-e820: [mem 0x000000005f730000-0x000000005f73ffff] ACPI data
[ 0.000000] BIOS-e820: [mem 0x000000005f740000-0x000000005f7effff] ACPI NVS
[ 0.000000] BIOS-e820: [mem 0x000000005f7f0000-0x000000005f7fffff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000e0000000-0x00000000efffffff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000fed13000-0x00000000fed19fff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000fed1c000-0x00000000fed9ffff] reserved
※cat /proc/iomemで詳細な物理メモリレイアウトを見られる。
81. 1.アドレス変換機能 – 物理メモリレイアウト(7)*
・物理アドレスマップの作成手順(3)
2.物理アドレスマップ作成
・コールスタック
start_kernel() [ver4.2 init/main.c:497]
→setup_arch() [ver4.2 arch/x86/kernel/setup.c:862]
→setup_memory_map() [ver4.2 arch/x86/kernel/e820.c:1085]
→x86_init.resources.memory_setup() [関数ポインタで以下を呼び出し]
→default_machine_specific_memory_setup() [ver4.2 arch/x86/kernel/e820.c:1047]
・append_e820_map()関数でe820map構造体に格納
・struct e820map構造体 [ver4.2 arch/x86/include/uapi/asm/e820.h:64]
e820インスタンス(ver4.2 arch/x86/kernel/e820.c:42)
e820インスタンスは編集用,e820_saveインスタンスは保存用
90. 2.メモリ保護機能(4)
・セグメントへのアクセスチェック(3)
・特権レベルチェック(2) – DSレジスタ更新時の保護
MAX(CPL,RPL) > DPL ⇒ 保護違反
(・CPL≦DPL⇒ロード可能
(・RPL≦DPL⇒ロード可能
ex.特権レベルとRPLの目的
GDT
セグメントセレクタ
※ユーザーがシステムコールにRPL=0のセレクタを渡し、カーネル領域にアクセスする事も出来てしまう。
⇒RPL=0のセレクタを渡しても、カーネルはRPL=3に書換え、カーネル領域にアクセス不可にする。
この様な、特権レベルを下げる目的でRPLを用いる。
インデックス DPL
3 0
4 3
インデックス TI RPL セレクタ CPL アクセス可否
4 0 3 0x23 3 DPL=RPL=CPL
可能。ユーザがユーザ領域にアクセス
3 0 0 0x18 0 DPL=RPL=CPL
可能。カーネルがカーネル領域にアクセス
3 0 3 0x1B 0 CPL=DPL≠RPL
ユーザがカーネル領域にアクセス