Linux设备树源码分析chapter1:内核自解压阶段

内核自解压阶段

该阶段与设备树有关的代码只是为了适配低版本没有设备树功能的uboot,高版本的uboot是不需要在这个阶段做与设备树相关的操作的

源文件arch\arm\boot\compressed\head.S

如果你使用的uboot和kernel版本相对较新(均支持设备树),那么内核自解压部分所做的工作和设备树毫无关系,but,but,but,如果你正在使用的uboot较老(不支持设备树)而你使用的内核版本却需要设备树的方式启动,那么在内核自解压阶段就需要额外做一些工作了,多出来的这部分工作由以下二宏来决定,废话不多说,上代码

#ifdef CONFIG_ARM_ATAG_DTB_COMPAT
		/*
		 * OK... Let's do some funky business here.
		 * If we do have a DTB appended to zImage, and we do have
		 * an ATAG list around, we want the later to be translated
		 * and folded into the former here. No GOT fixup has occurred
		 * yet, but none of the code we're about to call uses any
		 * global variable.
		*/

		/* Get the initial DTB size */
		ldr	r5, [r6, #4]
#ifndef __ARMEB__
		/* convert to little endian */
		eor	r1, r5, r5, ror #16
		bic	r1, r1, #0x00ff0000
		mov	r5, r5, ror #8
		eor	r5, r5, r1, lsr #8
#endif
		/* 50% DTB growth should be good enough */
		add	r5, r5, r5, lsr #1
		/* preserve 64-bit alignment */
		add	r5, r5, #7
		bic	r5, r5, #7
		/* clamp to 32KB min and 1MB max */
		cmp	r5, #(1 << 15)
		movlo	r5, #(1 << 15)
		cmp	r5, #(1 << 20)
		movhi	r5, #(1 << 20)
		/* temporarily relocate the stack past the DTB work space */
		add	sp, sp, r5

		stmfd	sp!, {r0-r3, ip, lr}
		mov	r0, r8
		mov	r1, r6
		mov	r2, r5
		bl	atags_to_fdt

		/*
		 * If returned value is 1, there is no ATAG at the location
		 * pointed by r8.  Try the typical 0x100 offset from start
		 * of RAM and hope for the best.
		 */
		cmp	r0, #1
		sub	r0, r4, #TEXT_OFFSET
		bic	r0, r0, #1
		add	r0, r0, #0x100
		mov	r1, r6
		mov	r2, r5
		bleq	atags_to_fdt

		ldmfd	sp!, {r0-r3, ip, lr}
		sub	sp, sp, r5
#endif

		mov	r8, r6			@ use the appended device tree

		/*
		 * Make sure that the DTB doesn't end up in the final
		 * kernel's .bss area. To do so, we adjust the decompressed
		 * kernel size to compensate if that .bss size is larger
		 * than the relocated code.
		 */
		ldr	r5, =_kernel_bss_size
		adr	r1, wont_overwrite
		sub	r1, r6, r1
		subs	r1, r5, r1
		addhi	r9, r9, r1

		/* Get the current DTB size */
		ldr	r5, [r6, #4]
#ifndef __ARMEB__
		/* convert r5 (dtb size) to little endian */
		eor	r1, r5, r5, ror #16
		bic	r1, r1, #0x00ff0000
		mov	r5, r5, ror #8
		eor	r5, r5, r1, lsr #8
#endif

		/* preserve 64-bit alignment */
		add	r5, r5, #7
		bic	r5, r5, #7

		/* relocate some pointers past the appended dtb */
		add	r6, r6, r5
		add	r10, r10, r5
		add	sp, sp, r5
dtb_check_done:
#endif

宏定义CONFIG_ARM_APPENDED_DTB

老版本的uboot并不支持设备树,那如果想以设备树的方式启动内核,那怎么办呢?将dtb追加到zImage后不就行了,即如果该宏被使能,那么在内核自解压时会认为设备树也在zImage这个文件里面,但假如我故意加载了一个并未追加设备树的zImage,这部分代码就起作用了,它会校验设备树的合法性(其实很简单,就是比较一下内存中设备树的前4个字节是否为0xd00dfeed)

/*
 *   r0  = delta
 *   r2  = BSS start
 *   r3  = BSS end
 *   r4  = final kernel address (possibly with LSB set)
 *   r5  = appended dtb size (still unknown)
 *   r6  = _edata
 *   r7  = architecture ID
 *   r8  = atags/device tree pointer
 *   r9  = size of decompressed image
 *   r10 = end of this image, including  bss/stack/malloc space if non XIP
 *   r11 = GOT start
 *   r12 = GOT end
 *   sp  = stack pointer
 *
 * if there are device trees (dtb) appended to zImage, advance r10 so that the
 * dtb data will get relocated along with the kernel if necessary.
 */

		ldr	lr, [r6, #0]  找到设备树的起始位置
#ifndef __ARMEB__
		ldr	r1, =0xedfe0dd0		@ sig is 0xd00dfeed big endian
#else
		ldr	r1, =0xd00dfeed     设备树前四个字节的Magic数据
#endif
		cmp	lr, r1  校验设备树是否存在
		bne	dtb_check_done		@ not found

宏定义CONFIG_ARM_ATAG_DTB_COMPAT

该宏的功能是将uboot的ATAGS传参升级成设备树,如果你仔细看了代码,你会发现该宏起作用的前提条件是“CONFIG_ARM_APPENDED_DTB”宏被打开,也就是说要让ATAGS升级为设备树的前提条件是你使用的uboot不支持设备树。

如果没有使能此宏定义,你uboot中的bootargs参数是无法传递给内核的comandline的,所以如果你把所有uboot想传递给内核的参数都已经提前写进了设备数里,那你就不需要使能该宏了,但假如你想让你的uboot传参仍然能有效的传给内核,那么只能使能该宏,将传参更新到设备树中对应的节点

这里面有一个重要的函数“atags_to_fdt”,就是这个函数将ATAGS传参转成了设备树里的参数。
在这里插入图片描述

注意,就是这个地方,将uboot种的bootargs环境变量赋值到了设备树下的chosen节点

おすすめ

転載: blog.csdn.net/weixin_42314225/article/details/118198634