内存初始化过程

1, 物理内存信息的获取

 0x15中断,功能号:E820H, E801H, E88H

见文件:linux/arch/i386/boot/setup.S

      执行完上面的代码后,内存信息被分为多条信息放在E820MAP位置处,每个信息条目长20字节,包含一个内存区间的信息,条目数放在E820NR处。即实际上条目信息被放到了empty_zero_page的偏移为E820MAP(即0x2d0)处,条目数被放到偏移为E820NR(即0x1e8)处。

 

2, start_kernel()->setup_arch() 

       setup_arch()中与内存有关的主要工作为初始化一些与物理页面管理有关的数据结构,如描述整个物理内存信息的e820变量,描述内存结点的pg_data_t对象,启动时低端内存分配器bootmem_data对象,以及最终物理页面的主要管理机构zone-buddy system。

 

 

      setup_memory_region()主要是把第一步中获得的内存信息从empty_zero_page中拷到e820变量中来。因为内存信息报告的区段有可能是凌乱的,比如重叠,顺序颠倒等,所以setup_memory_region()首先调用sanitize_e820_map()原地将信息进行整理,再调用copy_e820_map()将信息拷贝到e820变量中。如果信息有误,Linux保守的估计两个内存区段来初始化e820变量。

      setup_memory()主要完成高低端内存的划分,启动时低端内存分配器bootmem_data对象的初始化,并将e820中低端内存导入此分配器进行管理。

      setup_memory()调用find_max_low_pfn()进行高低端内存的划分;所谓低端内存是指内核直接映射的内存,高端内存指内核不直接映射的内存。因为Linux将3GB~4GB范围的1GB线性地址用于内核空间,而4GB顶端的128MB线性地址空间用于vmalloc以及fixed-address特殊映射,还剩下1GB-128MB=896MB的线性地址可用于直接映射物理内存,所以在物理内存充足的情况下,至少有896MB物理内存是直接映射到内核空间的,称为低端内存;大于896MB的不能直接映射到内核空间(因为线性地址不够)称为高端内存。显然896为低端内存的最大值提供了一个限定。然而,高低端内存的划分还必须可以由人为介入(由启动参数控制),尤其是当物理内存小于896MB的时候,在这种情况下,没有理由规定内核必须将所有的内存都直接映射到3GB~4GB中,所以可以通过highmem_pages变量来指定将多少内存“不用于”直接映射,即将多少内存用于高端内存。调用完find_max_low_pfn()以后,以下变量被设置:

      max_low_pfn: 低端内存的终止页框号

      max_pfn:         内存的终止页框号,即实际使用的物理页框数。它可能会小于真正存在的物理页框总数(e820中的最大页框数), 例如大于896MB的物理内存数多于用户指定的高端内存数时,以用户指定的为准,这样实际上有很多页框不会被使用。

     接着setup_memory()设置高端内存界限。highstart_pfn = max_low_pfn; highend_pfn = max_pfn; 显然[max_low_pfn, max_pfn)为高端内存。然后init_bootmem()初始化启动时内存分配器,用于在伙伴系统及slab分配器建立之前分配内存。分配器初始化后用register_bootmem_low_pages()将所有的低端内存页框纳入其管理之下。至此就可以使用此分配器将某些特殊作用的内存页面设置为保留(即永久性占有),或是使用其分配内存等等。

      paging_init()主要是设置swapper_pg_dir页全局目录,并使用之导入cr3,以及初始化伙伴系统管理机构,即内存结点对象和各个zone。pagetable_init()用来设置swapper_pg_dir页全局目录, 此页目录为其它进程页全局目录之内核空间映射的创建提供模板。此外还应该注意从实模式到保护模式时swapper_pg_dir的内容以及pg0, pg1, empty_zero_page这几个页面的位置(分别在内核映射起始处的第2,3,4,5页,实模式到保护模式切换时,线性空间0~8MB和0xc0000000~0xc0000000+8MB都映射到物理内存0~8MB上,这个8MB映射的页表就是pg0, pg1,即swapper_pg_dir[0]/swapper_pg_dir[768]指向pg0, swapper_pg_dir[1]/swapper_pg_dir[769]指向pg1)。paging_init()->zone_sizes_init()->free_area_init()->free_area_init_core()完成内存结点及zone的初始化,至此伙伴系统管理结构初始化完成,只等放入页面了。

      register_memory()主要是给内存注册总线地址空间。重点关注对总线地址空间的管理,两棵resoure树(iomem_resource/ioport_resource)。

 

3, start_kernel()->mem_init()

      运行到此,伙伴系统管理数据结构已初始化完毕,接着就只需要往里面放入物理页面了。mem_init()主要就做这件事。其调用free_pages_init()一方面把启动时分配器中空闲的低端内存页面放入伙伴系统,另一方面直接把[highstart_pfn, highend_pfn)中的高端内存页面放入伙伴系统。

 

物理页面到了zone-buddy system中,往后就简单多了。 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值