目次: Linux
Linuxのページディレクトリを見ていると0xc000 0000以降(※)はページディレクトリエントリがあるのに、その先のページテーブルがありません。なぜこれで動くんでしょう?
調べてみると、なるほど、トリックがありました。
LinuxはCR4のPSEビット(Page Size Extension、ビット4)を1にして、4MB/4KBどちらのサイズでも使えるようにしています。
確かめ方は、右Alt + ScrLockを押してレジスタダンプすると簡単でしょうか?以下のようなメッセージが出るはずです。Pentium Proから導入されているはずですので、未対応というのはそうそうないかと…。
Pid: 0, comm: swapper EIP: 0060:[<c01019bd>] CPU: 0 EIP is at default_idle+0x31/0x59 EFLAGS: 00010246 Not tainted (2.6.18-6-486 #1) EAX: 00000000 EBX: 00000800 ECX: c1101040 EDX: c030e000 ESI: 00099100 EDI: c0302800 EBP: 003a7007 DS: 007b ES: 007b CR0: 8005003b CR2: c02bd7f4 CR3: 07175000 CR4: 00000690 [<c0101a1c>] cpu_idle+0x37/0x4c [<c03105fa>] start_kernel+0x270/0x272
肝心なのはCR4レジスタの値です。CR4レジスタが0x0000 0690、2進数だと0110 1001 0000ですから、ビット4(ビット0から数えるので、右から5番目)のPSEビットが1になっていることが分かります。
(※)カーネルが使うリニアアドレス用のマッピングで、物理メモリ先頭896MB分を仮想アドレス0xc000 0000へマップしています。
物理: 0x0000 0000 .... 0x37ff ffff
リニア: 0xc000 0000 .... 0xf7ff ffff
というマッピングです。
じゃあ4MBと4KBの区別はどこでやってるのさ?というと、ページディレクトリテーブルの要素である、ページディレクトリエントリでやっています。インテルのマニュアルによれば、ページディレクトリエントリの構成は以下のようになっています。
細かい説明は後述しますが、PSビット(Page Size、ビット7)が1になっていれば4MBのページを指し、0ならば4KBのページを使うことを意味します。
128MBの実メモリを割り当てた仮想マシン上でLinuxを起動して、適当なプロセスのページテーブルをダンプしてみると、768要素目から以下のようなページディレクトリエントリが見受けられます。
128MBしか実メモリがないので、768〜799番目(4MB x 32ページ)までしか値が埋まりません。余った800番目以降は別の用途に使われます。
768: 0x000001e3, 0x004001e3, 0x008001e3, 0x00c001e3, 772: 0x010001e3, 0x014001e3, 0x018001e3, 0x01c001e3, 776: 0x020001e3, 0x024001e3, 0x028001e3, 0x02c001e3, 780: 0x030001e3, 0x034001e3, 0x038001e3, 0x03c001e3, 784: 0x040001e3, 0x044001e3, 0x048001e3, 0x04c001e3, 788: 0x050001e3, 0x054001e3, 0x058001e3, 0x05c001e3, 792: 0x060001e3, 0x064001e3, 0x068001e3, 0x06c001e3, 796: 0x070001e3, 0x074001e3, 0x078001e3, 0x07c001e3, 800: 0x00000000, 0x00000000, 0x07baf067, 0x00000000,
772番目を例に取ると、0xc100 0000〜0xc13f ffffの4MB分のアドレスをマップしています。0x010001e3は2進数だと0001 0000 0000 0000 0001 1110 0011ですので、先ほどの図に当てはめてみると、
4MBのページングを使っているのはカーネル用のリニアアドレス(0xc000 0000〜)だけのようです。他のページディレクトリエントリにはPSビットが設定されていません。ページ番号の指す先には、もう一段ページテーブルがあり、その先にやっと4KBのページがあります。
理由ですが、インテルのマニュアルによると4MBと4KBのページは別のTLBに置かれるので、カーネルのように頻繁に使うコードやデータは4MBページに置いておくと、フラッシュされなくて良いよ、ってなことが書いてあります。また、ページサイズが大きければTLBミスも少ないよ、ってな解説もあります。恐らくそんな理由です。
絵にしてみるとこんな感じでしょうか。間違ってるかも…。
サイズはアドレスの範囲を意味するのではなくてテーブル自体の大きさのことです。ページディレクトリテーブル(一段目のテーブル)も、ページテーブル(二段目のテーブル)も 4バイトx 1024要素なので同じ4KBですよ、って言いたかっただけです。
< | 2008 | > | ||||
<< | < | 05 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
合計:
本日: