linux内存管理 (三) 一系列的文章 讲述了 两个时间点 中的过程
1. 内核被加载到内存
2. 内核执行到 start_kernel
linux内存管理 (四) 想尽可能的叙述 从 start_kernel 到启动完成 过程中 ,启动相关的内存设置
当我们在讨论内存管理时,我们基于什么讨论
.code .rodata .data .bss .stack .heap
指令地址 数据地址
运行(物理)地址 链接地址 虚拟地址
-----------------------内存
主存
片上ram
-----------------------其他硬件
MMU(包括TLB)
cache
write buffer
CP15 协处理器
内存管理机制建立过程
时间与时刻 | 注释 | 起点 | 终点 | 该阶段使用的动态内存分配器名称 | 动态分配器提供的申请内存的API |
---|
第一阶段A(可选)[1] | 压缩内核加压缩,加载解压缩后的内核 | arch/arm/boot/compressed/head.S 的start | arch/arm/kernel/head.S的stext | 简单的内存分配器[2] | include/linux/decompress/mm.h 中定义的 malloc 和 free |
第一阶段B[3] | 建立页表,开MMU | arch/arm/kernel/head.S的stext | arch/arm/kernel/head.S 中的 __turn_mmu_on 返回 | 无动态内存分配器 | 无 |
第一阶段C | 建立以位图为基础的bootmem | arch/arm/kernel/head.S 中的 __turn_mmu_on 返回 | start_kernel -> setup_arch -> paging_init -> bootmem_init-> arm_bootmem_init 返回 | 无动态内存分配器 | 无 |
第一阶段完成点 | 建立了bootmem[4]供第二阶段使用 | - | - | - | - |
第二阶段 | 建立以page为基础的budddy,并销毁bootmem | start_kernel -> setup_arch -> paging_init -> bootmem_init-> arm_bootmem_init 返回 | start_kernel -> mm_init -> mem_init 返回 | bootmem | alloc_bootmem |
第二阶段完成点 | 建立了buddy供之后的所有阶段使用 | - | - | - | - |
第三阶段 | 以buddy为基础,开始建立slab | start_kernel -> mm_init -> mem_init 返回 | start_kernel -> mm_init -> kmem_cache_init 返回 | buddy | alloc_pages |
第三阶段完成点 | 建立了 slab供之后的所有阶段使用 | - | - | - | - |
linux运行情况 | 存在buddy,slab分配器 | start_kernel -> mm_init -> kmem_cache_init 返回 | 关机 | buddy/slab | alloc_pages/kmalloc |
注意:
[1]:第一阶段A是可选的,当bootloader 加载的内核是压缩的,则需要阶段A;否则不需要
第一阶段A和第一阶段B可被视为两个系统,A可被视为B的loader.
[2]:在 arch/arm/kernel/head.S的stext 开始运行时,该 "简单的内存分配器" 瞬间就不存在了
[3]:之所以强调第一阶段B是因为,这个过程中开启了MMU,相关地址概念发生了根本性的变化
开启前要关心 链接地址 和 运行地址(运行时的物理地址)
开启瞬间所有全局符号的 链接地址 不再是 链接地址 , 而是 虚拟地址
开启后要关心 物理地址 和 运行地址(运行时的物理地址)
参考 [linux内存管理 (三) 7 内核启动从start到start_kernel过程中的相关地址在内存中的分布](https://blog.csdn.net/u011011827/article/details/107827291)
[4]:bootmem 是过程中的产物,不是最终的产物,在buddy建立之前(free_all_bootmem_core返回时)就被释放了