在linux kernel初始化完成之后,系统中的内存分配和回收是由伙伴系统来管理,但是在kernel 初始化阶段时内存的分配和释放是由memblock管理,memblock在系统启动阶段进行简单的内存管理,记录物理内存的使用情况。本篇博客主要介绍在系统启动阶段memblock 的初始化过程。
linux-4.10/init/main.c
482 asmlinkage __visible void __init start_kernel(void)
483 {
484 char *command_line;
485 char *after_dashes;
...
508 setup_arch(&command_line);
...
673 rest_init();
674 }
bootloader 做好一些初始化工作后,将kernel Image加载到内存后,然后就跳到kernel 部分的代码继续执行,跑的先是汇编部分的代码,和体系结构相关,做好各种各样的设置,初始化好c运行环境,然后就跳到kernel 的第一个c函数start_kernel(),所以我们先从start_kernel()开始介绍,在start_kernel()中会调用setup_arch()完成体系结构相关的初始化。
linux-4.10/arch/arm64/kernel/setup.c
232 void __init setup_arch(char **cmdline_p)
233 {
234 pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());
235
236 sprintf(init_utsname()->machine, UTS_MACHINE);
237 init_mm.start_code = (unsigned long) _text;
238 init_mm.end_code = (unsigned long) _etext;
239 init_mm.end_data = (unsigned long) _edata;
240 init_mm.brk = (unsigned long) _end;
241
242 *cmdline_p = boot_command_line;
243
244 early_fixmap_init();
245 early_ioremap_init();
246
247 setup_machine_fdt(__fdt_pointer); //从fdt获取memroy 相关信息
...
265 arm64_memblock_init();
...
316 }
我们以arm64为例,setup_arch()中会完成memblock 的初始化,到这里我们有点疑惑了,__fdt_pointer 是在哪里初始化的。
首先我们要了解在长按电源键开机时,首先是芯片内部的一段程序跑起来,把flash 上的bootloader 加载并运行起来,然后bootloader 做好一些硬件的初始化后,将kernel 的镜像加载到内存中,并跳转到kernel 去执行。整个过程还有其他的许多细节,比如kernel 自解压,这里我们只需要关注linux kernel相关的细节,其他就不做过多介绍。bootloader 除了加载kernel 部分,还会把DTB加载到内存中,在跳转到kernel 执行时,会把DTB 数据的在内存中物理地址传过来。
这里我们回过头来看一下在跑start_kernel()之前,kernel 做了些什么。
在linux-4.10/arch/arm64/kernel/head.S
221 ENTRY(stext)
222 bl preserve_boot_args
223 bl el2_setup // Drop to EL1, w0=cpu_boot_mode
224 adrp x23, __PHYS_OFFSET
225 and x23, x23, MIN_KIMG_ALIGN - 1 // KASLR offset, defaults to 0
226 bl set_cpu_boot_mode_flag
227 bl __create_page_tables
228 /*
229 * The following calls CPU setup code, see arch/arm64/mm/proc.S for
230 * details.
231 * On return, the CPU will be ready for the MMU to be turned on and
232 * the TCR will have been set.
233 */
234 bl __cpu_setup // initialise processor
235 b __primary_switch
236 ENDPROC(stext)
上面贴出的是arm64 平台对应的汇编代码,我们认为linux kernel 部分代码就是从stext部分的汇编代码开始。
241 preserve_boot_args:
242 mov x21, x0 // x21=FDT
243
244 adr_l x0, boot_args // record the contents of
245 stp x21, x1, [x0] // x0 .. x3 at kernel ent