内核自解压阶段
该阶段与设备树有关的代码只是为了适配低版本没有设备树功能的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节点