Linux arm64 bootmem_init 初始化详细分析之-arm64_memory_present

linux内核版本:linux-4.4.y  基于arm64分析

推荐文章:http://www.voidcn.com/article/p-qtnltdel-up.html (Linux内存管理中的SPARSEMEM)

start_kernel -> setup_arch -> paging_init -> bootmem_init -> arm64_memory_present

arm64_memory_present,对于memblock管理的每一个memory region,为其创建mem_section结构体的内存空间,分配内存通过memblock模块进行,然后分配的mem_section类型的指针,指向静态定义的全局的mem_section指针数组,在分配mem_section类型的指针时,分配了一个PAGE的空间,SECTION_PER_ROOT * sizeof(struct mem_section),其中SECTION_PER_ROOT表示每个root中有多少个SECTION,sparse memory中使用1个PAGE能容纳多少个SECTION表示一个ROOT,即1个PAGE

 /* Record a memory area against a node. */ 
                    //start 为memory region的物理起始地址的pfn,end为物理结束地址的pfn                                      
 void __init memory_present(int nid, unsigned long start, unsigned long end)     
 {                                                                               
     unsigned long pfn;                                                          
                                                                                 
     start &= PAGE_SECTION_MASK;  // 保留起始pfn对应的 section num,section内的偏移mask为0                                                 
     mminit_validate_memmodel_limits(&start, &end); // 验证 start 是否超过最大物理的地址,或着end超过最大物理地址                               
     for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) {   //以section为单位,建立 mem_section结构体的内存空间,并不是分配 struct page 所占内存空间                  
         unsigned long section = pfn_to_section_nr(pfn);  // 取pfn对应的section num                        
         struct mem_section *ms;                                                 
                                                                                 
         sparse_index_init(section, nid);
            // 根据section num,首先判断此section属于哪个root section,然后判断此root section是否存在
            // 如果存在,那么返回 -EEXIST,如果不存在,那么调用sparse_index_alloc,分配一个 mem_section
            // 大小为1个page,分配成功,则将此结构体指针指向 静态定义的 mem_section指针数组,按照root section num存放
            // 因为1个page中存放固定数量的mem_section结构体,个数为:PAGE_SIZE/sizeof(struct mem_section) = SECTION_PER_ROOT
            // 假设SECTION_PER_ROOT = 4,即一个ROOT中存放4个mem_section的结构体,那么假设section num为13,那么,此section
            // 便在 13 / 4 = 3 ,即mem_section[3]指针数组中(注:此处的mem_section不是结构体,而是静态全局变量) 
            // 所以此函数的作用为,根据section num,找出在哪个 mem_section的root中,如果mem_section[root]中的指针为空,那么
            // 需要分配此 root mem_section的内存空间(大小为一个page),分配方式为 memblock模块,此时 slab is not available,
            // 通过sparse_index_alloc函数操作,分配内存通过 memblock_virt_alloc_node	 


        set_section_nid(section, nid);  
			// 另外还有一个全局静态数组,section_to_node_table,数组大小为系统中 SECTION大小,以此section num为索引,
			// 设置此 mem_section 的 node id,因为 arm64中使用的是UMA,未使用NUMA,所以,nid都为0                                        
                                                                                 
         ms = __nr_to_section(section); 
			// 如果section对应的mem_section的ROOT不存在,返回NULL,如果存在,则取此ROOT内的偏移
			// 例如 section为 13,SECTION_PER_ROOT = 4,则 13 在 mem_section[3] 中,取mem_section[3][1]
			// 即 ROOT内的偏移为多少,即可取得 此section对应的mem_section的地址    

        // 第一次初始化时,section_mem_map为空,所以执行下面的                                     
         if (!ms->section_mem_map)                                               
             ms->section_mem_map = sparse_encode_early_nid(nid) |                
                             SECTION_MARKED_PRESENT;     
      
				// sparse_encode_early_nid(nid) 此函数 nid << SECTION_NID_SHIFT
				// SECTION_MARKED_PRESENT     1<<0
				// 将 nid存放在 ms->section_mem_map 中,且将mem_section marke 为 present,此时并未分配 struct page结构体的内存空间                        
     }                                                                           
 }                                                                               

综上分析,memory_present根据memblock的memory region的start pfn,end pfn,来分配全局静态变量mem_section数组对应的指针,根据 start pfn,将start pfn中 mem_section位保留,低于mem_section的位设置位0,然后取得 mem_section的section number,根据此number,计算此number对应的root,然后以root为索引,在 全局 mem_section数组中找到root mem_section,然后再根据number,找到在 root mem_section中的具体的mem_section

分配好了 memory region 对应的 mem_section数据结构后,初始化mem_section对应的数据成员,这里将 mem_section中的section_mem_map 进行初始化,即将nid放在section_mem_map中,置位present位,表示此mem_section有对应的物理内存,可以为其分配 struct page结构体的内存空间,那么接下来的工具就是初始化 ms->section_mem_map,分配struct page结构体对应的内存空间,然后指向ms->section_mem_map

另外,此函数中将nid放在了两个地方,一个是ms->section_mem_map中,一个是全局静态数组section_to_node_table,具体为啥要设置这两处,通过搜索 section_to_node_table 的引用,发现只有 page_to_nid 这个函数有使用到此全局静态数组,所以此全局静态数组的设置的意义为,通过struct page结构体指针找到对应的nid,仅此而已

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

科技之光666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值