分类: LINUX
2009-05-03 16:18:57
下面将介绍start_kernel关于每个内存初始化函数。
在内核启动函数中,使用全局变量kernel_param即内核参数,同时调用了下面的内存初始化函数:
page_address_init()//这个函数初始化页地址,使用链表将其链接起来。
setup_arch()//内存初始化,这个函数是相当重要的,下面将详细地对这个函数进行功能上的总结。
这个函数设置了cpu引导数据,对前期CPU数据进行了初始化,以及对一些硬件数据进行了设置,(这里所讨论的一切都是在i386体系结构中进行讨论的,而且内存设为1GB)。同时设置了全局变量max_low_pfn,所调用的函数是setup_memory()(这个函数设置了min_low_pfn全局变量,min_low_pfn=0,还设置了全局变量max_low_pfn=896MB/4KB以及max_pfn=1GB/4kb,highstart_pfn=max_low_pfn,highend_pfn=max_pfn,这里的highstart_pfn以及highend_pfn使用来进行高端内核空间页面的记录的。最后,这个函数调用了函数setup_bootmem_allocator()函数,对于这个函数的详细解释在后面章节会说到,就是设置了引导内存bootmem的设置)。之后,一个相当有意思且非常重要的函数paging_init()函数被调用来初始化页表。同时还调用了zone_sizes_init()来初始化节点数据和zone数据。在执行完setup_arch()之后,节点管理数据node_data[0]初始化完毕,同时三个管理区的各个数据段也初始化完毕,这时,就开始setup_per_cpu_area()函数。但是这个函数在单个CPU系统中为
空操作,就直接过渡到build_all_zonelists(). setup_per_cpu_areas();单CPU系统中为空操作
build_all_zonelists();这个函数调用函数set_zonelist_order()将current_zonelist_order设置为2,
page_alloc_init();
cpuset_init_early();
mem_init();
kmem_cache_init();
setup_per_cpu_pageset();
pgtable_cache_init();
proc_caches_init();
cpuset_init();
paging_init函数的作用详解:
调用函数pagetable_init函数来为内核映射建立适当的页表,在这个函数被调用执行之前,系统一直是运行在引导进程所构造的页表中的。如果我们是在本地硬件进行引导的,那么这个页表则是在head.S文件中构造的,并且不运行在PAE模式下。这个页表的根是swapper_pg_dir,任何情况下paravirt_pagetable_setup_start()将会为其余的初始化工作进行适当地设置。pagetable_init函数调用kernel_physical_mapping_init函数初始化内核物理页表的映射,这个映射是最终映射。同时调用了page_table_range_init来对固定内存
进行了相应的映射处理以及permanent_kmaps_init()作永久内核映射初始化。
zone_sizes_init
这个函数调用add_active_range()函数实现对全局变量early_node_map数组的初始化,初始化的数据结果为:
这个函数的结果为:
3120 early_node_map[i].nid = nid=0;
3121 early_node_map[i].start_pfn = start_pfn=0;
3122 early_node_map[i].end_pfn = end_pfn=highend_pfn;
3123 nr_nodemap_entries = i + 1=1;
同时调用函数free_area_init_nodes()函数(即初始化节点的空闲区域),函数free_area_init_nodes()初始化所有
的节点链表和管理数据区,这个函数将会为每一个活动节点调用free_area_init_node进行处理。并使用add_active_range函数所提供
的数据来计算每个节点的每个管理区以及对应洞的大小。free_area_init_node函数设置了节点的node_id值以及节点node起始页表号
。同时计算了节点的页表总数,调用calculate_node_totalpages()计算节点的总页数,并在caculate_node_totalpages()函数中设置
了node_data[0]->node_spanned_pages和node_data[0]->node_present_pages,这里的node_data[0]是一全局变量,用来跟踪节点信息.在caculate_spanned_pages中计算了包含洞节点的大小以及不包含动节点的大小。分别使用上面的两个变量来记录。之后调用函数alloc_node_mem_map(),在alloc_node_mem_map()函数中有一个全局变量node_remap_alloc_vaddr.这个函数为页描述符分配空间。并将所分配的装载页描述符的起始地址赋给全局变量mem_map,mem_map是在/linux/mm/memory.c文件中定义的全局变量,用来进行页描述符的管理的。接着zone_sizes_init()调用函数free_area_init_core来设置管理区数据结构。这里又引入了一个全局变量zone,这个函数的工作就是初始化这个全局变量。在这个函数中初始化了节点锁node_data[0]->node_size_lock,初始化了kswapd页换出守护进程使用的等待队列node_data[0]->kswapd_wait,将kswapd将要创建的空闲块大小取对数的值初始化为0,并使用一个for循环来设置三个管理区的各个数据段。到此为止,zone_sizes_init的工作已经完成了。
chinaunix网友2009-06-16 17:54:54
“这时,就开始setup_per_cpu_area()函数。但是这个函数在单个CPU系统中为 空操作。。。。” LZ确定单cpu时此函数为空操作吗? 空操作的意思即为,不为单cpu分配内存空间?? 最近也在看这一块 感觉这一点和LZ的理解有偏差 例如:/proc/diskstats 虚拟文件下的数据就是在io操作完成后,通过per_cpu_ptr()方法将所需的值添加到每个cpu对应的缓存区(具体在_disk_stats_add方法中调用的) 如果按LZ所言 那岂不是单cpu时不会保存这些数据 然后/proc下也就取不到这些数据了?? 不知道是不是我理解有错误~~~ 愿与LZ探讨~~