paging_init()の2行目で実行するsparse_init()を見る前にここで使っている関数を先に軽く見ておく。
alloc_usemap_and_memmap()はこのようなI/Fの関数。 引数の最後のdataはalloc_func()の一番目の引数として使う。
469 static void __init alloc_usemap_and_memmap(void (*alloc_func) 470 (void *, unsigned long, unsigned long, 471 unsigned long, int), void *data)
変数宣言部は特に目立ったことはなし。
473 unsigned long pnum; 474 unsigned long map_count; 475 int nodeid_begin = 0; 476 unsigned long pnum_begin = 0; 477
0からNR_MEM_SECTIONSまでのループで何をするかというと、まずpnumはセクション番号として使っていて、このセクションが存在するかをチェックして存在しなければcontinue。 セクションがあれば__nr_to_section()でセクション番号からmem_section構造体のデータを取得。 セクションの開始番号がpnum_beginに入る。
478 for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { 479 struct mem_section *ms; 480 481 if (!present_section_nr(pnum)) 482 continue; 483 ms = __nr_to_section(pnum); 484 nodeid_begin = sparse_early_nid(ms); 485 pnum_begin = pnum; 486 break; 487 }
次は先ほどのセクション開始番号の次からループを開始。最初のif文は先ほどのチェックと同じ。
488 map_count = 1; 489 for (pnum = pnum_begin + 1; pnum < NR_MEM_SECTIONS; pnum++) { 490 struct mem_section *ms; 491 int nodeid; 492 493 if (!present_section_nr(pnum)) 494 continue;
mem_section構造体からNUMAノードのIDを取得。
495 ms = __nr_to_section(pnum); 496 nodeid = sparse_early_nid(ms);
これは前回の記事の最後の方で↓のようなことをしているんだけど、これによりここでノードIDが取れる。
182 if (!ms->section_mem_map) 183 ms->section_mem_map = sparse_encode_early_nid(nid) | 184 SECTION_MARKED_PRESENT;
ノードが同じならmap_countを1増やしてcontinue。map_countはalloc_func()で使用する。
497 if (nodeid == nodeid_begin) { 498 map_count++; 499 continue; 500 }
ここでalloc_func()を呼んでメモリ確保する。
501 /* ok, we need to take cake of from pnum_begin to pnum - 1*/ 502 alloc_func(data, pnum_begin, pnum, 503 map_count, nodeid_begin);
sparse_init()ではこのalloc_func()にsparse_early_usemaps_alloc_node()を渡しているんだけど、今はメモリを確保するってことだけわかれば先に進めるのでとりあえず(゚ε゚)キニシナイ!!
ここも見たままですな。
504 /* new start, update count etc*/ 505 nodeid_begin = nodeid; 506 pnum_begin = pnum; 507 map_count = 1; 508 }
ループが終わったところでNR_MEM_SECTIONSまでのメモリチャンクを確保する。
509 /* ok, last chunk */ 510 alloc_func(data, pnum_begin, NR_MEM_SECTIONS, 511 map_count, nodeid_begin); 512 }
alloc_usemap_and_memmap()が終わったところでsparse_early_usemaps_alloc_node()を見てみる。 alloc_usemap_and_memmap()でノードが同じならmap_countをインクリメントしていたけど、それがsize * usemap_countで使われている。
342 static void __init sparse_early_usemaps_alloc_node(void *data, 343 unsigned long pnum_begin, 344 unsigned long pnum_end, 345 unsigned long usemap_count, int nodeid) 346 { 347 void *usemap; 348 unsigned long pnum; 349 unsigned long **usemap_map = (unsigned long **)data; 350 int size = usemap_size(); 351 352 usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid), 353 size * usemap_count);
sparse_early_usemaps_alloc_pgdat_section()は実際にメモリを確保する処理なんだけど、ここも実装は特に気にしなくて良いはずなので飛ばす。
エラー処理なので見るべきところはなし。
354 if (!usemap) { 355 printk(KERN_WARNING "%s: allocation failed\n", __func__); 356 return; 357 } 358
セクション数のループで配列のusemap_mapに先ほどsparse_early_usemaps_alloc_pgdat_section()でメモリを確保した変数をセット。 最後のcheck_usemap_section_nr()はチェック用の関数なので設定した内容に問題が無い限りは無視。
359 for (pnum = pnum_begin; pnum < pnum_end; pnum++) { 360 if (!present_section_nr(pnum)) 361 continue; 362 usemap_map[pnum] = usemap; 363 usemap += size; 364 check_usemap_section_nr(nodeid, usemap_map[pnum]); 365 } 366 }
これでalloc_usemap_and_memmap()の処理は読み終わり。
ちなみに、今呼んでいるコードはpaging_init()から呼ばれる関数なのでページングの設定中な訳だけどこの時点でもページングは有効になってます。 これはstart_kernel()が呼ばれた段階で既にcpuはlong modeになっているんですが、long modeではページングの使用が必須なのでブート時に使うようの設定がされています。 この辺のコードはφ(.. )メモシテオコウ linuxのlong modeへの移行処理で読んでます。
- 作者: 平田豊
- 出版社/メーカー: 工学社
- 発売日: 2011/07
- メディア: 単行本
- 購入: 1人 クリック: 48回
- この商品を含むブログ (5件) を見る