Linux記憶體初始化之sparse記憶體模型(二)
阿新 • • 發佈:2018-11-14
1.Linux記憶體模型
前面已經分析把實體記憶體新增到memblock以及給實體記憶體建立頁表對映,這裡我們分析sparse記憶體模型
在linux核心中支援3中記憶體模型,分別是flat memory model,Discontiguous memory model和sparse memory model。所謂memory model,其實就是從cpu的角度看,其實體記憶體的分佈情況,在linux kernel中,使用什麼的方式來管理這些實體記憶體
sparse記憶體框架圖
2 sparse初始化分析
函式呼叫關係:start_kernel->setup_arch->paging_init->bootmem_init->sparse_init
主要是給每個section分配一個pageblock bitmap點陣圖
每個section又可以分為若干個pageblock,每個pageblock的狀態佔4bit,所以一個section的pageblock bitmap大小為:
unsigned long usemap_size(void) { unsigned long size_bytes; size_bytes = roundup(SECTION_BLOCKFLAGS_BITS, 8) / 8; size_bytes = roundup(size_bytes, sizeof(unsigned long)); return size_bytes; } 其中SECTION_BLOCKFLAGS_BITS表示一個section中的pageblock bit數量 #define SECTION_BLOCKFLAGS_BITS \ ((1UL << (PFN_SECTION_SHIFT - pageblock_order)) * NR_PAGEBLOCK_BITS) NR_PAGEBLOCK_BITS值為4,pageblock_order值為10
void __init sparse_init(void) { unsigned long pnum; struct page *map; unsigned long *usemap; unsigned long **usemap_map; int size; size = sizeof(unsigned long *) * NR_MEM_SECTIONS; /*為每個section分配一個記憶體,使用者儲存bitmap記憶體地址 */ usemap_map = memblock_virt_alloc(size, 0); if (!usemap_map) panic("can not allocate usemap_map\n"); /*分配section的pageblock bitmap點陣圖記憶體 */ alloc_usemap_and_memmap(sparse_early_usemaps_alloc_node,(void *)usemap_map); for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) { if (!present_section_nr(pnum)) continue; usemap = usemap_map[pnum]; if (!usemap) continue; /*對映page虛擬地址???? */ map = sparse_early_mem_map_alloc(pnum); if (!map) continue; /*標記section為map狀態 */ sparse_init_one_section(__nr_to_section(pnum), pnum, map,usemap); } memblock_free_early(__pa(usemap_map), size); }
section的初始化
static int __meminit sparse_init_one_section(struct mem_section *ms,
unsigned long pnum, struct page *mem_map,
unsigned long *pageblock_bitmap)
{
if (!present_section(ms))
return -EINVAL;
ms->section_mem_map &= ~SECTION_MAP_MASK;
/*標記section為map狀態 */
ms->section_mem_map |= sparse_encode_mem_map(mem_map, pnum) |
SECTION_HAS_MEM_MAP;
/*section的bitmap */
ms->pageblock_flags = pageblock_bitmap;
return 1;
}