免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1152 | 回复: 0
打印 上一主题 下一主题

内存初始化 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-11-06 20:36 |只看该作者 |倒序浏览
本篇文章是对linux内存初始化部分进行的一个小小的总结。本文仅仅代表我个人的分析结果,如果有什么不对的地方,希望各位网友斧正,谢谢!
在这个内核初始化过程中,linux内存的初始活动可以说是最复杂的模块之一,内核中的所有运行程序都是在初始化启动阶段完成的,对于启动部分,本文不会给出太多的解析,但是有一点很有必要,就是给出内核数据在内存中的布局,这里首先给出详细的文字性描述。
在内存中,从第一个页框到_text处由两个部分组成,一个是不可用页框,另外一个是可用页框。_text~_etext部分存放的内核代码,_etext+1~_edata存放的是已初始化的内核数据,_edata+1 ~ _end是未初始化的内核数据。为了更容易地对内存管理有个直观地认识,了解这一点是很有必要的。
接下来就是从start_kernel开始讨论:
内存管理的第一步是通过一个中断来实现的,此中断由函数detect_memory()来调用,在detect_memory()函数中,执行INT 0x15,eax = 0xe820中断,得到的数据存放在boot_params.e820_map中.
下面是boot_params.e820_map的详细定义:
struct e820map {
    __u32 nr_map;
    struct e820entry map[E820_X_MAX];  
    /* 一般情况下E820_X_MAX的值为128 */
};
struct e820entry {
    __u64 addr;
    __u64 size;
    __u32 type;   
}__attribute__((packed));
addr是存储段的起始地址,size是存储段的大小,type是存储段的类型.
struct boot_params中含有一个struct e820entry类型的数组,长度为128,因为内存可分为不同的段,每个段对应着一个e820map字段,每个段所对应的类型和大小以及起始地址都不一样,boot_params结构体中的e820_entries字段保存的是内存中段的数量。在后面的内存管理初始化过程中将会大量地引用到boot_params这个变量.此变量中的信息对于内核初始化是相当重要的。
setup_arch()
对于初始化内核start_kernel来说,setup_arch()是一个相当重要的函数,此函数实现了对特定体系的初始化。下面将会详细地对setup_arch函数进行说明.
1、setup_arch第一步要做的就是保存head.S初始化的new_cpu_data数据到boot_cpu_data中,boot_cpu_data主要是保存CPU的相关信息。
2、start_kernel内核初始化函数中第一个内存管理函数由setup_memory_map()来实现,setup_memory_map()最终调用default_machine_specific_memory_setup()实现对e820内存图的优化,并根据boot_params中e820_map字段的值来设置变量e820的值。之后将e820的数据保存到e820_saved中,相当于备份。最后打印出内存分布图;
3、调用系统编译生成的数据来初始化init_mm的start_code,end_code,end_data以及.brk等字段,同时也初始化code_resource的start,end字段和data_resource的start,end字段以及bss_resource的start,end字段.
4、接下来,调用e820_end_of_ram_pfn()函数根据e820的数据来获得内存的最大值并由函数e820_end_pfn返回,保存在max_pfn字段中。
5、紧接着,调用find_low_pfn_range()设置一些基本的变量,并设置num_physpages的值;
6、调用init_memory_mapping()函数来初始化内存映射,在函数init_memory_mapping函数中先后调用下面的几个函数来设置内存相关数据:
(因为bootmem此时没有初始化)
find_early_table_space()
kernel_physical_mapping_init()
early_ioremap_page_table_range_init()
load_cr3()
reserve_early()
上面四个函数分别实现了下面的功能:
find_early_table_space所实现的功能是相当重要的,首先是确定了PUD和PMD以及PTE、固定内存映射等所有的选项所使用的内存空间的大小,之后从e820.emap数据字段中寻找到一块能够容纳所有表项的内存段,并设置table_start,table_end,table_top的值,这三个数据相当的重要,因为在后面的页表初始化阶段将会使用到这三个变量.之后两次调用kernel_physical_mapping_init()分别初始化了第一个2MB的页表以及之后所有内存的页表。同样的,early_ioremap_page_table_range_init()也实现了类似的功能。接下来使用load_cr3加载了寄存器cr3。最后,init_memory_mapping返回了所映射页的数量值,并将值保存在max_low_pfn_mapped中,max_pfn_mapped的值和ma_low_pfn_mapped的值相当。
7、接下来,setup_arch()调用initmem_init来初始化内存,这个函数设置了early_node_map,并调用了函数setup_bootmem_allocator()来设置引导启动阶段所涉及到的页映射位。setup_bootmem_allocator()调用find_e820_area函数来寻找一块空闲内存段,之后调用init_bootmem_node
函数设置NODE(0)->bdata字段,设置的值如下所示:
bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));
bdata->node_min_pfn = 0;
bdata->node_low_pfn = max_low_pfn;
并将bdata->node_bootmem_map指向的数据区初始化为全1,最终将after_init_bootmem设置为1。bdata->node_bootmem_map指向的数据为启动阶段用于临时映射的内存区。这个内存区在初始化的后阶段会被应用上。
8、之后,调用paging_init()进行页面初始化.paging_init()分别调用下面的几个函数来实现页面的初始化工作:
pagetable_init();
kmap_init();
sparse_init();
zone_sizes_init();
zone_sizes_init()最终调用free_area_init_nodes()来实现节点空闲区域的初始化:
void __init free_area_init_nodes(unsigned long *max_zone_pfn)
{
    for_each_online_node(nid) {
        free_area_init_node(nid, NULL, find_min_pfn_for_node(nid), NULL);
    }
}
free_area_init_node()函数调用alloc_node_mem_map()来为所有页描述符分配空闲区域,并让NODE_DATA(0)->node_mem_map指向这段内存区域。紧接着调用free_area_init_core()初始化系统中的所有内存管理区。在free_area_init_core()函数内部,内核调用zone_init_free_lists(zone)来初始化所有内存管理区内的空闲链表。在free_area_init_core()函数对每个内存管理区进行初始化的过程中,内核调用memmap_init_zone()初始化了所有的页描述符,下面是具体的初始化:
void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
        unsigned long start_pfn, enum memmap_context context)
{
    struct page *page;
    unsigned long end_pfn = start_pfn + size;
    unsigned long pfn;
    struct zone *z;
    ...
    z = &ZONE_DATA(nid)->node_zones[zone];
    for (pfn = start_pfn; pfn lru);
    }
}
到此为止,setup_arch()有关内存管理的内容已经完毕,经过这一番初始化后,内存初始化已经完成了特定系统的基本初始化,接下来,start_kernel开始构建内存管理的经典算法应用:伙伴系统和slab内存管理。
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/73521/showart_2088247.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP