linux内核源码分析--内核启动之,Linux内核源码分析之setup_arch (二)
1. 概述
接着上一篇《Linux内核源码分析之setup_arch (一)》继续分析,本文首先分析arm_memblock_init函数,而后分析内核启动阶段的是如何进行内存管理的。node
2. arm_memblock_init
该函数的功能比较简单,主要就是把meminfo中记录的内存条信息添加到memblock.memory中,而后把内核镜像所在内存区域添加到memblock.reserved中,arm_mm_memblock_reserve把页表所在内存区域添加到memblock.reserved中;若是使用了设备树,则使用arm_dt_memblock_reserve来保留所占用的内存,最后则是调用CPU相关的mdesc->reserve,其对应的调用为cpu_mem_reserve,该函数定义在cpu.c中。linux
/* arch/arm/mm/init.c */
void __init arm_memblock_init(...) {
for (i = 0; i < mi->nr_banks; i++)
memblock_add(mi->bank[i].start, mi->bank[i].size);
memblock_reserve(__pa(_stext), _end - _stext);
arm_mm_memblock_reserve();
arm_dt_memblock_reserve();
if (mdesc->reserve)
mdesc->reserve();
arm_memblock_steal_permitted = false;
memblock_allow_resize();
memblock_dump_all();
}
/* include/kernel/memblock.h */
struct memblock {
phys_addr_t current_limit;
struct memblock_type memory;
struct memblock_type reserved;
};
3. memblock_alloc
接下来就该执行paging_init函数了,在分析paging_init以前先来点内核启动阶段的内存管理相关的内容。从arm_memblock_init开始引入memblock数据结构,其做用是实现内核启动初期的内存管理功能,严格来讲,其生命周期到paging_init::bootmem_init为止,memblock_alloc调用流程以下。数据结构
实际查找空闲内存的函数为memblock_find_in_range_node,而该函数中真正实现空闲内存查找的是for_each_free_mem_range_reverse这个宏定义。函数
/* mm/memblock.c */
phys_addr_t memblock_find_in_range_node(...)
{
...
for_each_free_mem_range_reverse(i, nid, &this_start, &this_end, NULL) {
...
if (cand >= this_start)
return cand;
}
return 0;
}
该宏定义以下,然而其中又嵌套了一个函数Orz...源码分析
/* include/linux/memblock.h */
#define for_each_free_mem_range_reverse(i, nid, p_start, p_end, p_nid) \
for (i = (u64)ULLONG_MAX, \
__next_free_mem_range_rev(&i, nid, p_start, p_end, p_nid); \
i != (u64)ULLONG_MAX; \
__next_free_mem_range_rev(&i, nid, p_start, p_end, p_nid))
首先须要说明的是,memblock.reserved标识的区域表示的是已被占用的内存区域,memblock.memory中记录的是内存条信息。如今回到__next_free_mem_range_rev函数,代码段(1)(2)的目的是找出内存条上两个reserved区域之间的内存区域,即空闲区域。找到以后再通过代码段(3)对空闲区域的起始地址和结束地址进行修正,由于代码段(1)(2)只能保证空闲区与当前内存条存在交集,并不能保证该空闲区域彻底处于当前内存条之中,主要缘由在于没法保证这两个reserved区域都在当前内存条上。this
/* mm/memblock.c */
void __init_memblock __next_free_mem_range_rev(...)
{
struct memblock_type *mem = &memblock.memory;
struct memblock_type *rsv = &memblock.reserved;
...
/* (1) */
for ( ; mi >= 0; mi--) {
struct memblock_region *m = &mem->regions[mi];
phys_addr_t m_start = m->base;
phys_addr_t m_end = m->base + m->size;
...
/* (2) */
for ( ; ri >= 0; ri--) {
struct memblock_region *r = &rsv->regions[ri];
phys_addr_t r_start = ri ? r[-1].base + r[-1].size : 0;
phys_addr_t r_end = ri < rsv->cnt ? r->base : ULLONG_MAX;
...
/* (3) */
if (m_end > r_start) {
if (out_start)
*out_start = max(m_start, r_start);
if (out_end)
*out_end = min(m_end, r_end);
if (out_nid)
*out_nid = memblock_get_region_node(m);
...
return;
}
}
}
*idx = ULLONG_MAX;
}
至此,空闲区域的查找基本就结束了,回到memblock_find_in_range_node函数中,再检查一下该区域的起始地址和结束地址是否合法等等,最终就申请到了所请求大小的内存区域,最后只须要将这块内存区域标记为reserved状态就结束了内存分配的整个过程了。code
/* mm/memblock.c */
int memblock_reserve(phys_addr_t base, phys_addr_t size)
{
struct memblock_type *_rgn = &memblock.reserved;
return memblock_add_region(_rgn, base, size, MAX_NUMNODES);
}
4. 总结
arm_memblock_init函数首先把记录在meminfo记录的内存条信息转移到memblock.memory中,而后把已经使用的内存区域记录到memblock.reserved中,主要包括内核镜像所占用区域、页表区域以及设备树;
memblock_alloc经过memblock中的memory和reserved中记录的信息进行内存管理,每次申请到内存以后都在memblock.reserved中进行记录。
linux内核源码分析--内核启动之,Linux内核源码分析之setup_arch (二)相关推荐
- Linux Redis自动启动,Redis开机启动,Linux Redis设置开机启动
Linux Redis自动启动,Redis开机启动,Linux Redis设置开机启动 >>>>>>>>>>>>>> ...
- linux redis自动重启,Linux Redis自动启动,Redis开机启动,Linux Redis设置开机启动
Linux Redis自动启动,Redis开机启动,Linux Redis设置开机启动 >>>>>>>>>>>>>> ...
- android源码学习- APP启动流程(android12源码)
前言: 百度一搜能找到很多讲APP启动流程的,但是往往要么就是太老旧(还是基于android6去分析的),要么就是不全(往往只讲了整个流程的一小部分).所以我结合网上现有的文章,以及源码的阅读和调试, ...
- 【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )
Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...
- [kernel 启动流程] 前篇——vmlinux.lds分析
https://blog.csdn.net/ooonebook/article/details/52690132 以下例子都以project X项目tiny210(s5pv210平台,armv7架构) ...
- Android以太网框架情景分析之启动简介
Android以太网框架情景分析之启动简介 Android网络框架分析系列文章目录: Android P适配以太网功能开发指南 Android以太网框架情景分析之启动简介 Androi ...
- linux内核体系学习路径_Linux内核分析(一)linux体系简介|内核源码简介|内核配置编译安装...
从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底,同时在博文中如果那些地方有问题还请各位大神为我讲解. 今天我们会分析到以下内容: 1. Linux体系结构简介 ...
- 【Linux 内核】实时调度类 ⑤ ( 实时调度类 rt_sched_class 源码分析 | 结构体字段及函数指针分析 )
文章目录 一.rt_sched_class 结构体变量类型 sched_class 二.next 字段值 三.enqueue_task 函数指针值 四.dequeue_task 函数指针值 五.yie ...
- 低温linux内核启动readl,Linux内核启动流程分析(一)
很久以前分析的,一直在电脑的一个角落,今天发现贴出来和大家分享下.由于是word直接粘过来的有点乱,敬请谅解! S3C2410 Linux 2.6.35.7启动分析(第一阶段) 1.依据arch/ar ...
- 【Linux 内核】进程管理 ( 内核线程概念 | 内核线程、普通进程、用户线程 | 内核线程与普通进程区别 | 内核线程主要用途 | 内核线程创建函数 kernel_thread 源码 )
文章目录 一.内核线程概念 二.内核线程.普通进程.用户线程 三.内核线程.普通进程区别 四.内核线程主要用途 五.内核线程创建函数 kernel_thread 源码 一.内核线程概念 直接 由 Li ...
最新文章
- android h5弹窗,Android嵌套html5页面中alert 弹出框问题
- 示范园谋定小农户-丰收节交易会·万祥军:衔接现代农业
- linux中GDB详细使用手册
- create-react-app 构建的项目使用 mobx (说到底就是为了使用装饰器语法对 babel 做些配置...
- 物流配送系统设计java,ZigBee物流配送系统设计
- android sdk版本升级,个推 Android SDK 老版本升级2.9.+
- 基于systemverilog读写文件
- Docker 镜像基本命令操作
- 关于C++标准库中的数据抽象
- 【笔记】线性代数的本质
- python做问卷调查赚钱的软件_在网上做调查问卷能挣钱吗?靠谱吗
- Lipschitz连续
- 万字详解加拿大央行CBDC分析报告
- 了解arXiv,及arXiv的注册详细操作。
- 这个行业一半人月薪超过8千!
- 如何写出自媒体10W+爆文?
- 通信协议-GMSL(千兆多媒体串行链路)
- 我与安利美女过招;安利传销内幕揭秘! 转
- 孤尽训练营打卡日记day04--MySQL优化
- 《张孝祥JAVA就业培训教程》书摘