专栏名称: Jiau
目录
相关文章推荐
上海本地宝  ·  失业后医保怎么交? ·  4 天前  
51好读  ›  专栏  ›  Jiau

Linux内核源码分析之setup_arch (四)

Jiau  · 掘金  ·  · 2021-05-18 18:32

正文

阅读 16

Linux内核源码分析之setup_arch (四)

前言

Linux内核源码分析之setup_arch (三) 基本上把setup_arch主要的函数都分析了,由于距离上一篇时间比较久了,所以这里重新贴一下大致的流程图,本文主要分析的是bootmem_init函数。

代码分析

bootmem_init函数的结构如下:

find_limits通过存储在meminfo中的内存条信息得到低端内存和高端内存的页框编号,分别放入到min、max_low、max_high中。

static void __init find_limits(unsigned long *min, unsigned long *max_low,
          unsigned long *max_high)
{
 ...
 *min = bank_pfn_start(&mi->bank[0]);
 for_each_bank (i, mi)
  if (mi->bank[i].highmem)
    break;
 *max_low = bank_pfn_end(&mi->bank[i - 1]);
 *max_high = bank_pfn_end(&mi->bank[mi->nr_banks - 1]);
}
复制代码

arm_bootmem_init对低端内存区域进行管理,流程图如下:

在通过find_limits得到内存的起止页框号之后,通过bootmem_bootmap_pages计算得到需要分配bitmap的大小,分配好bitmap之后调用init_bootmem_node将起止页框号和bitmap信息写入到pgdat中。

/* arch/arm/mm/init.c */
static void __init arm_bootmem_init(unsigned long start_pfn,
 unsigned long end_pfn)
{
 ...
 boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
 bitmap = memblock_alloc_base(boot_pages << PAGE_SHIFT, L1_CACHE_BYTES,
    __pfn_to_phys(end_pfn));

 node_set_online(0);
 pgdat = NODE_DATA(0);
 init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn);
  ...
}
复制代码

最后就是把memblock管理的内存移交给bootmem来管理,对于memblock中的空闲区域通过free_bootmem将bitmap中对应的bit置零,而已经使用的内存,即memblock中对应的reserved的区域使用reserve_bootmem将bitmap中对应bit置1。

/* arch/arm/mm/init.c */
static void __init arm_bootmem_init(...)
{
 ...
 /* Free the lowmem regions from memblock into bootmem. */
 for_each_memblock(memory, reg) {
  ...
  free_bootmem(__pfn_to_phys(start), (end - start) << PAGE_SHIFT);
 }
 /* Reserve the lowmem memblock reserved regions in bootmem. */
 for_each_memblock(reserved, reg) {
  ...
  reserve_bootmem(__pfn_to_phys(start),
           (end - start) << PAGE_SHIFT, BOOTMEM_DEFAULT);
 }
}
复制代码

在设置好bitmap之后,接下来开始分配对应的page结构体,在分配page结构体内存之前,先统计出各个zone区域内的内存空洞,存放在zhole_size中。

/* arch/arm/mm/init.c */
static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
 unsigned long max_high)
{
 ...
 for_each_memblock(memory, reg) {
  ...
  if (start < max_low) {
   unsigned long low_end = min(end, max_low);
   zhole_size[0] -= low_end - start;
  }
#ifdef CONFIG_HIGHMEM
  if (end > max_low) {
   unsigned long high_start = max(start, max_low);
   zhole_size[ZONE_HIGHMEM] -= end - high_start;
  }
#endif
 }
 ...
 free_area_init_node(0, zone_size, min, zhole_size);
}
复制代码

统计好内存空洞之后开始分配page结构体所需要的内存空间,大致流程如下:

calculate_node_totalpages通过zones_size和zholes_size计算出内存页总数和真正可用的内存页数量,分别记录在pgdat->node_spanned_pages和pgdat->node_present_pages中。







请到「今天看啥」查看全文