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中。
/* mm/page_alloc.c */
void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
unsigned long node_start_pfn, unsigned long *zholes_size)
{
pg_data_t *pgdat = NODE_DATA(nid);
pgdat->node_id = nid;
pgdat->node_start_pfn = node_start_pfn;
calculate_node_totalpages(pgdat, zones_size, zholes_size);
alloc_node_mem_map(pgdat);
free_area_init_core(pgdat, zones_size, zholes_size);
}
alloc_node_mem_map根据pgdat->node_spanned_pages的大小确定需要分配的page结构体数量,这其中包括了内存空洞部分的区域,分配好之后将起始地址记录到pgdat->node_mem_map中,同时也记录在全局变量mem_map中。
/* mm/page_alloc.c */
static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
{
...
if (!pgdat->node_mem_map) {
...
start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1);
end = pgdat->node_start_pfn + pgdat->node_spanned_pages;
end = ALIGN(end, MAX_ORDER_NR_PAGES);
size = (end - start) * sizeof(struct page);
map = alloc_remap(pgdat->node_id, size);
if (!map)
map = alloc_bootmem_node_nopanic(pgdat, size);
pgdat->node_mem_map = map + (pgdat->node_start_pfn - start);
}
if (pgdat == NODE_DATA(0))
mem_map = NODE_DATA(0)->node_mem_map;
...
}
最后通过free_area_init_core初始化page结构体,大致流程如下:
主要作用是设置每个zone结构体的信息,比如zone的可用空间大小等信息,并把每个zone的page结构体初始化,记录自己所属的zone和node_id,同时把page结构体状态设置为PG_reserved,这里是无差别的设置的,至于空闲的内存页会在后续的mm_init::mem_init::free_all_bootmem中重新释放出来;另外,SetPageReserved是通过宏声明的,所以是无法找到该函数的,其定义在page-flags.h中。
总结
bootmem_init函数的作用是分配bitmap和page结构体所需要的空间,同时把已使用的和空闲的内存区域都标记到bitmap中,然后更新每个zone的内存信息,并把属于每个zone内存空间对应的page结构体进行初始化,且全部都设置为PG_reserved状态。
Linux内核源码分析之setup_arch (四)的更多相关文章
- Linux内核源码分析之setup_arch (二)
1. 概述 接着上一篇<Linux内核源码分析之setup_arch (一)>继续分析,本文首先分析arm_memblock_init函数,然后分析内核启动阶段的是如何进行内存管理的. 2 ...
- Linux内核源码分析之setup_arch (三)
1. 前言 在 Linux内核源码分析之setup_arch (二) 中介绍了当前启动阶段的内存分配函数memblock_alloc,该内存分配函数在本篇将要介绍paging_init中用于页表和内存 ...
- Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】
原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.c ...
- Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)
http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...
- Linux内核源码分析 day01——内存寻址
前言 Linux内核源码分析 Antz系统编写已经开始了内核部分了,在编写时同时也参考学习一点Linux内核知识. 自制Antz操作系统 一个自制的操作系统,Antz .半图形化半命令式系统,同时嵌入 ...
- Linux内核源码分析方法_转
Linux内核源码分析方法 转自:http://www.cnblogs.com/fanzhidongyzby/archive/2013/03/20/2970624.html 一.内核源码之我见 Lin ...
- Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】
原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://bl ...
- Linux内核源码分析方法
一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...
- 【转】Linux内核源码分析方法
一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...
随机推荐
- TypeScript TSConfig All In One
TypeScript TSConfig All In One tsconfig.json https://www.typescriptlang.org/tsconfig https://www.typ ...
- PerformanceObserver API All In One
PerformanceObserver API All In One 性能监控 https://developer.mozilla.org/en-US/docs/Web/API/Performance ...
- Node.js & ES modules & .mjs
Node.js & ES modules & .mjs Node.js v13.9.0 https://nodejs.org/api/esm.html https://nodejs.o ...
- Flutter: 判断是Android还是Ios
/// 在ui中使用下面的这个判断 Theme.of(context).platform == TargetPlatform.android /// 而不是 import 'dart:io' Plat ...
- React 函数式组件的 Ref 和子组件访问(useImperativeHandle)
引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...
- [转]Linux 线程实现机制分析 Linux 线程实现机制分析 Linux 线程模型的比较:LinuxThreads 和 NPTL
转载地址:https://www.cnblogs.com/MYSQLZOUQI/p/4233630.html 自从多线程编程的概念出现在 Linux 中以来,Linux 多线应用的发展总是与两个问题脱 ...
- [转]百度Appollo无人车Perception Module 分析
https://github.com/ApolloAuto/apollo/blob/master/docs/howto/modules/apollo1.5_perception_module_stud ...
- CSS中Position属性static、absolute、fixed、relative
在html中网页可以看成一个立体的空间,一个完整的页面是由很多个页面堆积形成的,如下图所示 CSS中Position属性有四个可选值,它们分别是:static.absolute.fixed.rel ...
- Javascript中的事件对象和事件类型
接上次看JS的事件冒泡和捕获,所以顺带就把事件相关的知识都看完好了 而且想到一个好的学习方法,第一天自己看,第二天把前一天学习的东西写下来,一方面可以当复习,一方面当重新整理并且分享 事件对象 事件处 ...
- CentOS6.4 Install oh-my-zsh
先安装zsh yum -y install zsh # 查看是否安装完成 cat /etc/shells /bin/sh /bin/bash /sbin/nologin /bin/dash /bin/ ...