在板子上电的uboot之后,便是linux内核的启动过程
在 Linux 内核启动过程中,最初的部分是由汇编代码完成的,主要负责进行最基础的硬件初始化、内存布局设置以及从低级模式(比如实模式或保护模式)切换到内核所需的更高级模式。例如,在 x86_64 架构下,这部分代码主要集中在 arch/x86/kernel/head_64.S (或 32 位系统下的 head.S)中。
在完成这些低级的初始化工作后,汇编代码会调用 C 语言编写的内核初始化入口函数——start_kernel()。这个函数定义在 init/main.c 中,标志着内核从汇编环境切换到 C 语言环境,接下来由 C 语言代码负责进一步的系统初始化工作和设备驱动加载等任务。
在基本的初始化后,系统会跳到 init/main.c 中的rest_init 内,创建1号进程和2号进程,并通过遍历的方式进行驱动模块的初始化。并开始运行命令行指定的第一个进程init=/linuxrc。
根据上文将此过程大概分为三个部分:引导、内核初始化、过渡倒rootfs三个阶段
一、引导:
uboot的初始文件为start.s,而内核初始化的初始文件为head.s

head.s 文件通常是用 汇编语言 编写的,特别是在 Linux 启动阶段(Booting Stage)中。这个文件的主要作用是完成早期的硬件初始化,并为后续的 C 语言代码(如 start_kernel)准备运行环境

二、内核初始化:
start_kernel 是内核启动的重要函数,在这过程种要进行从设备树到中断、定时器等等一系列的初始化,此过程已经由汇编语言转为C语言



三、过渡倒rootfs:
start_kernel函数结束后会跳转到rest_init函数,这过程会进行创建1号进程和2号进程,并通过遍历的方式进行驱动模块的初始化。并开始运行命令行指定的第一个进程init=/linuxrc。
0号进程:内核启动时由汇编及早期 C 代码创建的 idle 进程,它负责在系统空闲时运行,同时作为所有进程的根基。
1号进程:由 0号进程在 rest_init() 中 fork 出来的第一个用户空间进程(init),它承担了用户空间初始化和启动所有后续进程的任务。
2号进程(守护进程):即 kthreadd,它作为内核线程的管理者,负责后续内核线程的创建和管理。

跟踪方法:
正常我们开启Ctags后可以选定函数后敲击Ctrl + ] 键进行跟踪,当没法跳转时可以打开system.map 这个文件,先用Vim检索的方法找到对应的函数,获得对应的地址
获得地址之后使用交叉编译工具链进行定位目录路劲,例如用aarch64-linux-gnu-addr2line ffffff8008080000 -e vmlinux -f /*查找地址对应的文件位置
1、原理:aarch64-linux-gnu-addr2line 是专门为 AArch64 架构编译的版本,能够正确解析 ARMv8 架构的地址映射和指令集相关的符号信息,用于将二进制文件中的地址转换为对应的源代码文件和行号。之所以可以用该命令查找地址对应的文件位置。
2、使用方法:
命令格式 aarch64-linux-gnu-addr2line ffffff8008080000 -e vmlinux -f 中:
ffffff8008080000 是要查询的地址。
-e vmlinux 指定了包含符号信息的二进制文件。
-f 表示同时显示函数名。
工具通过查找 vmlinux 内部的调试信息,将该地址映射回源代码中的文件和行号。
system.map界面:

1万+

被折叠的 条评论
为什么被折叠?



