【嵌入式Linux】内核启动分析与源码跟踪

内核启动分析

  1. BIOS/UEFI阶段:计算机开机后首先会执行BIOS或UEFI程序,进行一些硬件初始化操作,如检查硬件配置信息、启动自检程序、加载操作系统引导程序等。
  2. Bootloader阶段:BIOS/UEFI会加载引导程序,比如GRUB等,这个引导程序会在屏幕上显示一个菜单,供用户选择要启动的操作系统,如果只有一个操作系统,那么该引导程序将自动启动内核。引导程序会根据用户选择或默认设置找到内核映像文件,加载到内存中。
  3. 内核启动自解压阶段:内核启动时,它首先会解压缩自身,然后进行一系列的初始化工作,如初始化CPU、内存管理、设备管理、文件系统等。其中,内存管理是最重要的一步,因为内核需要将系统中的所有可用内存映射到自己的地址空间中。
  4. 内核引导阶段:
  5. init进程启动阶段:当内核初始化完毕后,会启动init进程。在Linux系统中,init进程是用户空间中的第一个进程,它负责初始化系统环境,包括加载配置文件、启动系统服务等。
  6. 过渡到rootfs

跟踪线索

arch/arm64/kernel/head.S 入口

init/main.c start_kernel

kernel中敲make后会生成System.map,相关的函数名和地址都放里面了

通过地址追踪到函数所在的文件,使用交叉编译工具链的某个工具

//arch/arm64/kernel/vmlinux.lds.S 连接脚本:指定程序在代码段数据段中如何分配

通过它知道arm64的第一条就是_text

//第一条指令位置
	
{
   //System.map 函数 列表
ffffff8008080000 T _text  //第一条指令
ffffff8008081800 T vectors  //异常向量表
ffffff80096007f4 T start_kernel	 //内核初始化
}
//通过地址追踪到函数所在的文件,使用交叉编译工具链的addr2line工具
//vmlinux是所有调试信息还在的内核镜像,也在kernel-4.9目录下
$ aarch64-linux-gnu-addr2line ffffff8008080000 -e vmlinux -f /*查找地址对应的文件位置
 /home/yhai/kernel-4.9/arch/arm64/kernel/head.S:83     //这个文件的83行

$ aarch64-linux-gnu-addr2line ffffff8008081800 -e vmlinux -f
vectors
/home/yhai/kernel-4.9/arch/arm64/kernel/entry.S:393
 
 $aarch64-linux-gnu-addr2line ffffff80096007f4 -e vmlinux -f
  start_kernel
  /home/yhai/kernel-4.9/init/main.c:482

 */
 
{
   //arch/arm64/kernel/vmlinux.lds.S  连接脚本:指定程序在代码段数据段中如何分配
 21 OUTPUT_ARCH(aarch64)
 22 ENTRY(_text)  //入口地址
110 SECTIONS
111 {
   
130     .head.text : {
   
131         _text = .;    //代码段连接的时,第一条指令的位置
132         HEAD_TEXT
133     }
134     .text : {
              /* Real text segment        */
135         _stext = .;     /* Text and read-only data  */
136             __exception_text_start = .;
137             *(.exception.text)
138             __exception_text_end = .;
139             IRQENTRY_TEXT
140             SOFTIRQENTRY_TEXT
141             ENTRY_TEXT
        }
    }
}

入口(汇编部分)

//arch/arm64/kernel/head.S  入口
    __HEAD
_head:
	    //对应前面 ffffff8008080000 T _text
83    b   stext               // branch to kernel start, magic
ENTRY(stext)
    bl  preserve_boot_args  //保存u-boot传入的启动参数
    bl  el2_setup           //异常级别(权限)的设置:建议EL2级别,如不则下降到EL1 
                            //Drop to EL1, w0=cpu_boot_mode  
    bl  set_cpu_boot_mode_flag  // 按 ctrl+]  会跳到定义处,   按ctrl+o 会返回原位置
    bl  __create_page_tables //创建内存映射表
    bl  __cpu_setup         //初始化CPU(配置访问权限,内存地址划分)
                            //查找源码: vscode -> arch/arm64 -> 右键 在文件夹中查找 __cpu_setup -> mm/proc.S
    b   __primary_switch    //主切换
ENDPROC(stext)
1.保存传入的启动参数
/*
 * Preserve the arguments passed by the bootloader in x0 .. x3
 */
preserve_boot_args:
	mov	x21, x0		// x21=FDT   (X0里存放的是u-boot传入的设备树dtb的首地址)

	adr_l	x0, boot_args			// record the contents of
	stp	x21, x1, [x0]			// x0 .. x3 at kernel entry
	stp	x2, x3, [x0, #16]

	dmb	sy				// needed before dc ivac with
					    	// MMU off

	add	x1, x0, #0x20			// 4 x 8 bytes
	b	__inval_cache_range		// tail call
ENDPROC(preserve_boot_args)
2.异常级别(特权)设置
//el2级别下的初始设置(el2_setup):  是el2,则进行虚拟化设置,处理完后用w0保存cpu的异常级别(el1或推荐的el2)
ENTRY(el2_setup)
	msr	SPsel, #1			// We want to use SP_EL{1,2}
	mrs	x0, CurrentEL  //读取当前异常级别
	cmp	x0, #CurrentEL_EL2  //判断是EL2否
	b.ne	1f   //不是则跳到1f标号处
	mrs	x0, sctlr_el2

	msr	sctlr_el2, x0
	b	2f

1:	mrs	x0, sctlr_el1

	msr	sctlr_el1, x0
	mov	w0, #BOOT_CPU_MODE_EL1		// This cpu booted in EL1
	isb
	ret

2:
#ifdef CONFIG_ARM64_VHE
	/*
	 * Check for VHE being present. For the rest of the EL2 setup,
	 * x2 being non-zero indicates that we do have VHE, and that the
	 * kernel is intended to run at EL2.
	 */
	mrs	x2, id_aa64mmfr1_el1
	ubfx	x2, x2, #8, #4
#else
	mov	x2, xzr
#endif

	/* Hyp configuration.  虚拟化的配置*/
	mov_q	x0, HCR_HOST_NVHE_FLAGS
	cbz	x2, set_hcr
	mov_q	x0, HCR_HOST_VHE_FLAGS
set_hcr:
	msr	hcr_el2, x0
	isb

	/* Generic timers.  通用定时器设置*/
	mrs	x0, cnthctl_el2
	orr	x0, x0, #3			// Enable EL1 physical timers
	msr	cnthctl_el2, x0
	msr	cntvoff_el2, xzr		// Clear virtual offset

#ifdef CONFIG_ARM_GIC_V3
	/* GICv3 system register access  中断系统系统寄存器访问*/
	mrs	x0, id_aa64pfr0_el1
	ubfx	x0, x0, #24, #4
	cbz	x0, 3f

	mrs_s	x0, ICC_SRE_EL2
	orr	x0, x0, #ICC_SRE_EL2_SRE	// Set ICC_SRE_EL2.SRE==1
	orr	x0, x0, #ICC_SRE_EL2_ENABLE	// Set ICC_SRE_EL2.Enable==1
	msr_s	ICC_SRE_EL2, x0
	isb					// Make sure SRE is now set
	mrs_s	x0, ICC_SRE_EL2			// Read SRE back,
	tbz	x0, #0, 3f			// and check that it sticks
	msr_s	ICH_HCR_EL2, xzr		// Reset ICC_HCR_EL2 to defaults

3:
#endif

	/* Populate ID registers. */
	mrs	x0, midr_el1
	mrs	x1, mpidr_el1
	msr	vpidr_el2, x0
	msr	vmpidr_el2, x1

	/*
	 * When VHE is not in use, early init of EL2 and EL1 needs to be
	 * done here.
	 * When VHE _is_ in use, EL1 will not be used in the host and
	 * requires no configuration, and all non-hyp-specific EL2 setup
	 * will be done via the _EL1 system register aliases in __cpu_setup.
	 */
	cbnz	x2, 1f

	/* sctlr_el1 */
	mov	x0, #0x0800			// Set/clear RES{1,0} bits
	msr	sctlr_el1, x0

	/* Coprocessor traps. */
	mov	x0, #0x33ff
	msr	cptr_el2, x0			// Disable copro. traps to EL2
1:


	/* EL2 debug */
	mrs	x0, id_aa64dfr0_el1		// Check ID_AA64DFR0_EL1 PMUVer
	sbfx	x0, x0, #8, #4
	cmp	x0, #1
	b.lt	4f				// Skip if no PMU present
	mrs	x0, pmcr_el0			// Disable debug access traps
	ubfx	x0, x0, #11, #5			// to EL2 and allow access to
4:
	csel	x0, xzr, x0, lt			// all PMU counters from EL1
	msr	mdcr_el2, x0			// (if they exist)

	/* Stage-2 translation */
	msr	vttbr_el2, xzr

	cbz	x2, install_el2_stub

	mov	w0, #BOOT_CPU_MODE_EL2		// This CPU booted in EL2
	isb
	ret

install_el2_stub:
	/* Hypervisor stub */
	adrp	x0, __hyp_stub_vectors
	add	x0, x0, #:lo12:__hyp_stub_vectors
	msr	vbar_el2, x0       //设置异常向量表 基地址

	/* spsr */
	mov	x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
		      PSR_MODE_EL1h)
	msr	spsr_el2, x0
	msr	elr_el2, lr
	mov	w0, #BOOT_CPU_MODE_EL2		// This CPU booted in EL2
	eret
ENDPROC(el2_setup)
3.设置CPU启动时的异常级别标志

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值