就是塔塔的个人空间 https://www.eechina.com/space-uid-136863.html [收藏] [复制] [RSS]

博客

Linux内核启动流程-IMX6ULL开发板(一)

已有 448 次阅读2020-7-17 10:28 | Linux, 迅为IMX6ULL开发板

在前面的章节介绍了ubootLinux内核的一些相关内容。在来看Linux内核的大致启动流程,Linux内核的启动流程要比uboot复杂的多,涉及到的内容也更多,因此在本章节大致简单的了解一下Linux内核的启动流程。有兴趣的用户可以参考其他书籍或资料进行深入了解。

嵌入式linux内核的启动全过程主要分为三个阶段。第一阶段为内核自解压过程,第二阶段主要工作是设置ARM处理器工作模式、使能MMU、设置一级页表等,而第三阶段则主要为C代码,包括内核初始化的全部工作下面分别进行简单介绍。

基于迅为-IMX6ULL开发板

30.1 Linux内核启动(一):Linux内核自解压过程

Linux内核有两种映像格式:一种是非压缩内核,叫Image,另一种是它的压缩版本,叫zImage。zImage是Image经过压缩形成的,所以它的大小比Image小。但为了能使用zImage,必须在它的开头加上解压缩的代码,将zImage解压缩之后才能执行,因此它的执行速度比Image要慢一些

内核压缩和解压缩代码都在目录kernel/arch/arm/boot/compressed,编译完成后将产生head.omisc.opiggy.gzip.ovmlinuxdecompress.o这几个文件,head.o是内核的头部文件,负责初始设置;misc.o将主要负责内核的解压工作,它在head.o之后;piggy.gzip.o是一个中间文件,其实是一个压缩的内核(kernel/vmlinux),只不过没有和初始化文件及解压文件链接而已;vmlinux是没有(zImage是压缩过的内核)压缩过的内核,就是由piggy.gzip.ohead.omisc.o组成的,而decompress.o是为支持更多的压缩格式而新引入的。

uboot完成系统引导将Linux内核加载到内存之后,调用do_bootm_linux(),这个函数将跳转到kernel的起始位置。如果kernel没有被压缩,就可以启动了。如果kernel被压缩过,则要进行解压,在压缩过的kernel头部有解压程序。压缩过的kernel入口第一个文件源码位置在arch/arm/boot/compressed/head.S。它将调用函数decompress_kernel(),这个函数在文件arch/arm/boot/compressed/misc.c中,decompress_kernel()又调用arch_decomp_setup()进行设置,然后调用gunzip()将内核放于指定的位置。

函数decompress_kernel实现的功能:解压缩代码位于kernel/lib/inflate.cinflate.c是从gzip源程序中分离出来的,包含了一些对全局数据的直接引用,在使用时需要直接嵌入到代码中。gzip压缩文件时总是在前32K字节的范围内寻找重复的字符串进行编码, 在解压时需要一个至少为32K字节的解压缓冲区,它定义为window[WSIZE]inflate.c使用get_byte()读取输入文件,它被定义成宏来提高效率。输入缓冲区指针必须定义为inptrinflate.c中对之有减量操作。inflate.c调用flush_window()来输出window缓冲区中的解压出的字节串,每次输出长度用outcnt变量表示。在flush_window()中,还必须对输出字节串计算CRC并且刷新crc变量。在调用gunzip()开始解压之前,调用makecrc()初始化CRC计算表。最后gunzip()返回0表示解压成功。在内核启动时一般会看到这样的输出:

UncompressingLinux...done, booting the kernel.

当然有的内核没有这样的输出,是没有这一条打印语句。

30.2 Linux内核启动(二):ARM处理器相关设置

Linux内核自解压完成后,开始执行内核代码。内核的入口函数由链接脚本vmlinux.lds决定,需要编译内核源码,才会生成脚本文件。

首先分析Linux内核的链接脚本文件arch/arm/kernel/vmlinux.lds,通过链接脚本可以找到Linux内核的第一行程序是从哪里开始执行的。vmlinux.lds文件部分代码如下:

492 OUTPUT_ARCH(arm)

493 ENTRY(stext)

494 jiffies = jiffies_64;

495 SECTIONS

496 {

497 /*

498 * XXX: The linker does not define how output sections are

499 * assigned to input sections when there are multiple statements

500 * matching the same input section name. There is no documented

501 * order of matching.

502 *

503 * unwind exit sections must be discarded before the rest of the

504 * unwind sections get included.

505 */

506 /DISCARD/ : {

507 *(.ARM.exidx.exit.text)

508 *(.ARM.extab.exit.text)

509

......

645 }

493行的 ENTRY 指明了Linux内核入口函数为stext,因此要分析Linux内核第二阶段的启动流程,就得先从文件 arch/arm/kernel/head.S stext处开始分析。 

30.2.1 Linux内核入口函数stext

stextLinux内核的入口地址,在文件arch/arm/kernel/head.S中有如下内容:

/*

* Kernel startup entry point.

* ---------------------------

*

* This is normally called from the decompressor code. The requirements

* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,

* r1 = machine nr, r2 = atags or dtb pointer.

.....

*/

以上代码中的内容显示。Linux内核启动之前要求如下:

① 关闭MMU

② 关闭D-cache

③ 不用关心I-cache

④ r0 = 0

⑤ r1 = machine nr(机器ID号)

⑥ r2 = atags或者设备树(dts)首地址

Linux内核的入口点stext其实相当于内核的入口函数,stext函数代码如下:

80 ENTRY(stext)

......

91 @ ensure svc mode and all interrupts masked

92 safe_svcmode_maskall r9

93

94 mrc p15, 0, r9, c0, c0 @ get processor id

95 bl __lookup_processor_type @ r5=procinfo r9=cpuid

96 movs r10, r5 @ invalid processor (r5=0)?

97 THUMB( it eq ) @ force fixup-able long branch encoding

98 beq __error_p @ yes, error 'p'

99

......

107


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
返回顶部