paging_init()の2行目、sparse_init()のところを読む。
sparse_init()の関数にあるコメントを見るとやろうとしていることはなんとなくわかる。 ここで言っているaccumulated non-linear sectionsというのは前回までの記事で見てきた部分で、e820のメモリマップを取得して開いているところカーネルが管理できるようしたりしてた部分。
514 /* 515 * Allocate the accumulated non-linear sections, allocate a mem_map 516 * for each and record the physical to section mapping. 517 */ 518 void __init sparse_init(void)
では、実際に関数を見ていく。 最初は変数定義なので飛ばして。。。
520 unsigned long pnum; 521 struct page *map; 522 unsigned long *usemap; 523 unsigned long **usemap_map; 524 int size; 525 #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER 526 int size2; 527 struct page **map_map; 528 #endif 529
ここもまあ良いでしょう。
530 /* see include/linux/mmzone.h 'struct mem_section' definition */ 531 BUILD_BUG_ON(!is_power_of_2(sizeof(struct mem_section))); 532
ここではメモリアローケータが最大で何ページ分連続した領域を確保できるかのリミットを設定。この関数はCONFIG_HUGETLB_PAGE_SIZE_VARIABLEがyの時はこの関数内でオーダーの設定をするんだけど、CONFIG_HUGETLB_PAGE_SIZE_VARIABLEがnの場合はオーダーは10とコンパイル時に決定される。
533 /* Setup pageblock_order for HUGETLB_PAGE_SIZE_VARIABLE */ 534 set_pageblock_order();
ここは見たままと言えば見たままですな。現段階では本来のメモリーアローケーターが初期化されてないのでalloc_bootmem()が使われるという程度。ブートプロセス、ブート完了後どちらからでも呼ばれるような関数だとslab_is_available()を使って使用するアローケーターを変えたりもしている模様。
536 /* 537 * map is using big page (aka 2M in x86 64 bit) 538 * usemap is less one page (aka 24 bytes) 539 * so alloc 2M (with 2M align) and 24 bytes in turn will 540 * make next 2M slip to one more 2M later. 541 * then in big system, the memory will have a lot of holes... 542 * here try to allocate 2M pages continuously. 543 * 544 * powerpc need to call sparse_init_one_section right after each 545 * sparse_early_mem_map_alloc, so allocate usemap_map at first. 546 */ 547 size = sizeof(unsigned long *) * NR_MEM_SECTIONS; 548 usemap_map = alloc_bootmem(size); 549 if (!usemap_map) 550 panic("can not allocate usemap_map\n");
alloc_usemap_and_memmap()は前回の「linux:sparse_init()の前にalloc_usemap_and_memmap()を見ておくで調べた関数。メモリ確保する関数(sparse_early_usemaps_alloc_node())と、データを格納して欲しい変数のアドレスを渡す。 alloc_usemap_and_memmap()は2個の引数しか取らないから忘れがちになるけど、alloc_usemap_and_memmap()内でセクション0からNR_MEM_SECTIONSまでを検索して〜という感じのことをやっているのでデータはalloc_usemap_and_memmap()がセットしてくれる。なんてゆーか、alloc_usemap_and_memmapって名前なのにメモリ確保以上のことをしてくれるからだな。
551 alloc_usemap_and_memmap(sparse_early_usemaps_alloc_node, 552 (void *)usemap_map); 553
ここで渡すのはpage構造体。Arch Linuxの.configではCONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHERはyなのでここは実行される。
554 #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER 555 size2 = sizeof(struct page *) * NR_MEM_SECTIONS; 556 map_map = alloc_bootmem(size2); 557 if (!map_map) 558 panic("can not allocate map_map\n"); 559 alloc_usemap_and_memmap(sparse_early_mem_maps_alloc_node, 560 (void *)map_map); 561 #endif 562
セクション数のループで、セクション番号が存在しなければcontinueという今までも見てきたチェックがここでも。
563 for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { 564 if (!present_section_nr(pnum)) 565 continue; 566
インデックスpnumでusemap_mapにデータがあるかチェック。
567 usemap = usemap_map[pnum]; 568 if (!usemap) 569 continue; 570
セクション番号pnumに該当するpage構造体の取得。
571 #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER 572 map = map_map[pnum]; 573 #else 574 map = sparse_early_mem_map_alloc(pnum); 575 #endif 576 if (!map) 577 continue; 578
pageがあったらsparse_init_one_section()を呼ぶ。内容は後で。
579 sparse_init_one_section(__nr_to_section(pnum), pnum, map, 580 usemap); 581 } 582
vmemmap_populate_print_last()はログレベルをKERN_DEBUGでprintk()を使っているので通常のディストリビューションだとログは出ないですね。 最後に使った領域を開放して終わり。
583 vmemmap_populate_print_last(); 584 585 #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER 586 free_bootmem(__pa(map_map), size2); 587 #endif 588 free_bootmem(__pa(usemap_map), size); 589 }
これでsparse_init()が終わりなので、sparse_init_one_section()を見よう。 最初にセクションが存在しているかチェック。
230 static int __meminit sparse_init_one_section(struct mem_section *ms, 231 unsigned long pnum, struct page *mem_map, 232 unsigned long *pageblock_bitmap) 233 { 234 if (!present_section(ms)) 235 return -EINVAL; 236
まあ、ビット操作ですね。
237 ms->section_mem_map &= ~SECTION_MAP_MASK; 238 ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum) | 239 SECTION_HAS_MEM_MAP;
ビットの意味はinclude/linux/mmzone.hにある定義を見たほうが早いですね。
1143 /* 1144 * We use the lower bits of the mem_map pointer to store 1145 * a little bit of information. There should be at least 1146 * 3 bits here due to 32-bit alignment. 1147 */ 1148 #define SECTION_MARKED_PRESENT (1UL<<0) 1149 #define SECTION_HAS_MEM_MAP (1UL<<1) 1150 #define SECTION_MAP_LAST_BIT (1UL<<2) 1151 #define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1)) 1152 #define SECTION_NID_SHIFT 2
sparse_encode_mem_map()はこのような関数でページセクション番号を物理ページのへーじフレーム番号に変換しているらしい。
210 /* 211 * Subtle, we encode the real pfn into the mem_map such that 212 * the identity pfn - section_mem_map will return the actual 213 * physical page frame number. 214 */ 215 static unsigned long sparse_encode_mem_map(struct page *mem_map, unsigned long pnum) 216 { 217 return (unsigned long)(mem_map - (section_nr_to_pfn(pnum))); 218 } 219
あとはsparse_init()から渡ってきたusemapをpageblock_flagsに代入して保存。
240 ms->pageblock_flags = pageblock_bitmap; 241 242 return 1; 243 }
これでpaging_init()が2行読み終わった( ´∀`)bグッ!
- 作者: Daniel P. Bovet,Marco Cesati,高橋浩和,杉田由美子,清水正明,高杉昌督,平松雅巳,安井隆宏
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/02/26
- メディア: 大型本
- 購入: 9人 クリック: 269回
- この商品を含むブログ (68件) を見る