初始化_Linux的内存初始化
看了很多关于linux内存管理的文章还是云里雾里,听了很多关于linux内存管理的课程还是一头雾水。其实很多时候造成不懂的原因不是资料太少,恰恰是资料太多,而且各个内核版本的差异,32位64位的不同,文章的胡编乱造等都给读者带来疑惑。本着对内存深度剖析的态度,希望以版本kernel-4.14,架构AARCH64为专题做个内存管理的架构性整理。
这篇文章我们先来看下linux在启动过程中的初始化。
创建启动页表:
在汇编代码阶段的head.S文件中,负责创建映射关系的函数是create_page_tables。create_page_tables函数负责identity mapping和kernel image mapping。
identity map:是指把idmap_text区域的物理地址映射到相等的虚拟地址上,这种映射完成后,其虚拟地址等于物理地址。idmap_text区域都是一些打开MMU相关的代码。
kernel image map:将kernel运行需要的地址(kernel txt、rodata、data、bss等等)进行映射。
arch/arm64/kernel/head.S:ENTRY(stext) bl preserve_boot_args bl el2_setup // Drop to EL1, w0=cpu_boot_mode adrp x23, __PHYS_OFFSET and x23, x23, MIN_KIMG_ALIGN - 1 // KASLR offset, defaults to 0 bl set_cpu_boot_mode_flag bl __create_page_tables /* * The following calls CPU setup code, see arch/arm64/mm/proc.S for * details. * On return, the CPU will be ready for the MMU to be turned on and * the TCR will have been set. */ bl __cpu_setup // initialise processor b __primary_switchENDPROC(stext)
__create_page_tables主要执行的就是identity map和kernel image map:
__create_page_tables:...... create_pgd_entry x0, x3, x5, x6 mov x5, x3 // __pa(__idmap_text_start) adr_l x6, __idmap_text_end // __pa(__idmap_text_end) create_block_map x0, x7, x3, x5, x6 /* * Map the kernel image (starting with PHYS_OFFSET). */ adrp x0, swapper_pg_dir mov_q x5, KIMAGE_VADDR + TEXT_OFFSET // compile time __va(_text) add x5, x5, x23 // add KASLR displacement create_pgd_entry x0, x5, x3, x6 adrp x6, _end // runtime __pa(_end) adrp x3, _text // runtime __pa(_text) sub x6, x6, x3 // _end - _text add x6, x6, x5 // runtime __va(_end) create_block_map x0, x7, x3, x5, x6 ......
其中调用create_pgd_entry进行PGD及所有中间level(PUD, PMD)页表的创建,调用create_block_map进行PTE页表的映射。关于四级页表的关系如下图所示,这里就不进一步解释了。
汇编结束后的内存映射关系如下图所示:
当执行完上面的map之后,MMU就已经打开了并且开始进入C代码运行阶段,那么下一步就要对dtb进行映射了。
fixmap区之dtb map:
在执行setup_arch中,会最先进行early_fixmap_init(),这个函数就是用来map dtb的,但是它只会建立dtb对应的这段物理地址中间level的页表entry,而最后一个level的页表映射则通过setup_machine_fdt函数里的fixmap_remap_fdt来创建。
void *__init fixmap_remap_fdt(phys_addr_t dt_phys){ void *dt_virt; int size; dt_virt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO); if (!dt_virt) return NULL; memblock_reserve(dt_phys, size); return dt_virt; }
fixmap_remap_fdt主要是为fdt建立地址映射,在该函数的最后,顺便就调用memblock_reserve保留了该段内存。
可以看出dtb的映射采用的是fixmap,所谓fixmap就是固定映射,它需要我们明确的知道想要映射的物理地址,并把这段地址映射到想要映射的虚拟地址上。当然这里固定映射还有些片面,因为在fixmap机制实现上,也有支持动态分配虚拟地址的功能,这个功能主要用于临时fixmap映射(这个临时映射就是用来执行early ioremap使用的。),而dtb的映射属于永久映射。
fixmap区之early ioremap:
对于一些硬件需要在内存管理系统起来之前就要工作的,我们就可以使用这种机制来映射内存给这些硬件driver使用。各个模块在使用完early ioremap的地址后,需要尽快把这段映射的虚拟地址释放掉,这样才能反复被其他模块继续申请使用。
early_ioremap_init会调用early_ioremap_setup:
可见它的实现是依赖fixmap的,所以它必须要在early_fixmap_init之后才能运行。
注意:如果想要在伙伴系统初始化之前进行设备寄存器的访问,那么可以考虑early IO remap机制。
至此我们已经知道dtb和early ioremap都是在fixmap区的,如下图:
系统内存的布局:
完成dtb的map之后,内核可以访问这一段的内存了,通过解析dtb中的内容,内核可以勾勒出整个内存布局的情况,为后续内存管理初始化奠定基础。这一步主要在setup_machine_fdt中完成。这里就不看代码了,其调用流程是:setup_machine_fdt->early_init_dt_scan->early_init_dt_scan_nodes
就像注释中所示内核根据dtb的不同node勾勒出choosen node,root node,memory node相应内存区域。
除了这3个node,还有一个reserved-memory node,它是在上面讲到dtb map的时候fixmap_remap_fdt函数做的。下面我们看下这4个node的具体实现。
choosen node
该节点有一个bootargs属性,该属性定义了内核的启动参数,比如mem= xx,此外,还处理initrd相关的property,并保存在initrd_start和initrd_end这两个全局变量中。
root node
与内存无关,暂时不详述,以后有机会讲到device tree系列再详述。
memory node
通过memblock_add加入到memblock.memory对应的memblock_type链表中进行管理。
接下来到arm64_memblock_init函数:
void __init arm64_memblock_init(void){...... memblock_reserve(__pa_symbol(_text), _end - _text); 1.kernel image保留区 #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) { memblock_reserve(initrd_start, initrd_end - initrd_start); 2.initrd保留区 /* the generic initrd code expects virtual addresses */ initrd_start = __phys_to_virt(initrd_start); initrd_end = __phys_to_virt(initrd_end); } #endif early_init_fdt_scan_reserved_mem(); 3.dts中配置为保留的区域......}
reserve内核代码、数据区等(_text到_end那一段,具体的内容可以参考内核链接脚本)
保留initital ramdisk image区域(从initrd_start到initrd_end区域)
reserved-memory node 如下所示:
完成:
通过上面的一系列操作,需要动态管理的内存已经被放到了memory type和reserved type这两个region中了,现在内存已经被memblock模块所管理了,这只是启动后的第一步,后续内存才会加入到伙伴系统去管理。
添加极客助手微信,加入技术交流群
长按,扫码,关注公众号
麻烦给个好看!
初始化_Linux的内存初始化相关推荐
- 【嵌入式开发】ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )
文章目录 一. 内存 简介 1. 两大内存分类 ( 1 ) DRAM 简介 ( 定期刷新 | 速度慢 | 成本低 ) ( 2 ) SRAM 简介 ( 不需刷新 | 存取速度快 | 功耗大 | 成本高 ...
- Linux内存初始化(一)
一.前言 一直以来,我都非常着迷于两种电影拍摄手法:一种是慢镜头,将每一个细节全方位的展现给观众.另外一种就是快镜头,多半是反应一个时代的变迁,从非常长的时间段中,截取几个典型的snapshot,合成 ...
- X-007 FriendlyARM tiny4412 u-boot移植之内存初始化
<<<<<<<<<<<<<<<<<<<<<<<<< ...
- 【Linux 内核 内存管理】Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )
文章目录 一.ARM64 架构体系内存分布 二.Linux 内核启动源码 start_kernel 三.内存初始化源码 mm_init 四.内存初始化源码 mem_init 一.ARM64 架构体系内 ...
- Linux内存初始化(C语言部分)
这篇博客接着上篇博客,继续介绍Linux内核启动过程中内存的初始化过程. 相比于汇编代码,分析C代码有一个优势,因为在之前的汇编代码中已经开启了分页模式,所以可以通过一些symbol直接在某些函数上设 ...
- Linux内存初始化(汇编部分)
之前有几篇博客详细介绍了Xen的内存初始化,确实感觉这部分内容蛮复杂的.这两天在看Linux内核启动中内存的初始化,也是看的云里雾里的,想尝试下边看边写,在写博客的过程中慢慢思考,最后也能把自己的思考 ...
- FD.io VPP:vlib buffer pool(vlib_buffer) 内存初始化
Table of Contents vlib buffer创建过程 vlib_buffer相关内存初始化 1.函数一开始就查询numa的个数 2.遍历numa节点来初始化 3.查询系统大页大小. 4. ...
- linux内核初始化卡死,armlinux内核启动--内存初始化管理
linux版本:2.6.36 相关数据结构 arch/arm/include/asm/setup.h #ifdef CONFIG_ARCH_LH7A40X # define NR_BANKS 16 # ...
- Linux内存初始化(四) 创建系统内存地址映射
一.前言 经过内存初始化代码分析(一)和内存初始化代码分析(二)的过渡,我们终于来到了内存初始化的核心部分:paging_init.当然本文不能全部解析完该函数(那需要的篇幅太长了),我们只关注创建系 ...
最新文章
- OpenGL学习入门之VS2010环境配置 [转]
- 一家两位Fellow大满贯!北大谢涛当选ACM Fellow,与胞兄谢源完成会师
- 自己动手实现简易代码生成器、采用文本模板文件生成服务层、服务层接口代码的做法参考...
- android设计招式之美,麦可网Android设计招式之美
- C++ opengl 绘制地面
- java之yield(),sleep(),wait()区别详解-备忘笔记
- Go语言之map练习
- IDEA中实现接口时注解@Override报错的解决方法
- portal认证 只能重定向80和443请求_华为防火墙内置Portal认证报文交互
- PHP中普通类、抽象类、接口之间的关联
- Coded UI- Run Coded UI in WinForm
- 2019,一年一度的高考季来临,作文又成热门话题
- java实现发送匿名邮件,帮帮忙!现在要实现邮件发送(还必须要匿名发送)!该怎么解决...
- Noi 十连测 Zbox loves meizi
- 程序员如何保护自己的颈椎?颈椎操
- Web安全之认证机制
- 分布式系统关注点——如何去实施「负载均衡」? 1
- 一级计算机浏览器题加收藏夹,2016年计算机一级考试上机操作重难点突破
- 低功耗蓝牙BLE之修改广播间隔等参数
- 史上最牛实习生爆料:我在赶集网的两个月
热门文章
- 从IT的角度思考BIM(二):模式与框架
- 面向对象基本原则-转载
- C语言课后习题(35)
- 单片机实现水位控制C语言,单片机课程设计 水位自动控制.doc
- PHP百度收录量查询接口源码,PHP百度收录量查询接口源码
- Oracle 20c 新特性:DIAGNOSTICS_CONTROL 对诊断事件的安全管控
- 每秒570000的写入,MySQL如何实现?
- 普通用户竟这样执行xp_cmdshell存储过程!
- 面对行业难题,华为云邀请物联网全行业拿出“亮剑”精神
- IAP:物联网终端软件升级技术