【X210学习--Kernel启动流程】

X210学习–Kernel启动流程

总体流程概述

1.uboot 调用do_bootm_linux 中的 theKernel (0, machid, bd->bi_boot_params);进入kernel部分代码
该函数最终会通过r0,r1,r2这三个寄存器分别把0、machid、传递传参的首地址传给kernel。
2.Kernel 的入口 在head.S中ENTRY(stext)处,此阶段是汇编阶段,此阶段会解析r0,r1,r2(也就是uboot的传参)最终会通过进入start_kernel,进入到c语言环境执行。

Uboot部分

前面初始化准备略过,从do_bootm函数开始看

do_bootm:

1.对内核镜像类型做判断(uImage/zImage/fit(设备树)),
2.对函数传参做判断,从而决定从默认地址启动还是传参地址
3.获取镜像地址(也就是镜像存放在DDR的地址0x30008000)
4.保存镜像地址后续作为kernel入口
在这里插入图片描述
5.把image_header 保存到images.legacy_hdr_os_copy中
在这里插入图片描述
6.跳转到do_bootm_linux中去执行
在这里插入图片描述

do_bootm_linux:

1.通过传参找到kernel入口,保存到ep中,然后把theKernel指向ep
在这里插入图片描述在这里插入图片描述
2.对机器码处理
在这里插入图片描述

3.对传参tag做处理

4.跳转执行kernel代码
在这里插入图片描述
更多请参考:
UBOOT——启动内核

Kernel阶段

经过前面uboot的准备工作,通过theKernel (0, machid, bd->bi_boot_params); 开始进入到kernel部分开始执行。
注意:kernel镜像(zImage)的前部分代码是未经压缩直接可以使用的,后半部分代码由前面一小部分未压缩的代码解压缩后再使用。后面会介绍解压缩程序。

首先要知道kernel的入口,就要从连接脚本vmlinux.lds.S开始分析
、
在这里插入图片描述
可以看出入口符号是stext,经过搜索可以确认是在head.S文件中
在这里插入图片描述

head.S以及汇编启动阶段分析:

首先是文件前面两个宏需要注意,这里分别定义了kernel运行时的虚拟地址(0xC0008000)和对应的物理地址(0x30008000)
:TEXT_OFFSET 在代码中找不到,是编译生成的,需要在编译好的kernel源码树下grep "TEXT_OFFSET" * -nR 查找
在这里插入图片描述

ENTRY(stext)分析

在这里插入图片描述

1.__lookup_processor_type
读取并且检验CPU ID号
2.__lookup_machine_type
检验机器码
3.__vet_atags
检验uboot传参是否正确
4.__create_page_tables
创建页表。
linux内核本身被连接在虚拟地址处,因此kernel希望尽快建立页表并且启动MMU进入虚拟地址工作状态。但是kernel本身工作起来后页表体系是非常复杂的,建立起来也不是那么容易的。kernel想了一个好办法。
kernel建立页表其实分为2步:
第一步,kernel先建立了一个段式页表(和uboot中之前建立的页表一样,页表以1MB为单位来区分的),这里的函数就是建立段式页表的。段式页表本身比较好建立(段式页表1MB一个映射,4GB空间需要4096个页表项,每个页表项4字节,因此一共需要16KB内存来做页表),坏处是比较粗不能精细管理内存;
第二步,再去建立一个细页表(4kb为单位的细页表),然后启用新的细页表废除第一步建立的段式映射页表。

内核启动的早期建立段式页表,并在内核启动前期使用;内核启动后期就会再次建立细页表并启用。等内核工作起来之后就只有细页表了。
5.__switch_data
在这里插入图片描述
可以看出,__switch_data是个函数指针列表。可以看出后面执行的话先执行__mmap_switched
但是,此处不是直接执行__switch_data,而是先把该地址存放在r13中,然后执行__enable_mmu
在这里插入图片描述
6.__enable_mmu
经过分析可看到在__enable_mmu最后调用__turn_mmu_on

7.__turn_mmu_on
在这里插入图片描述
此处最后把r3给到r3,然后pc指针指向r3执行。也就是上面的__switch_data的地址(也就是__mmap_switched的地址)去执行。

8.__mmap_switched
在这里插入图片描述
由上图代码可以看出,最终会执行start_kernel,至此跳转到c语言环境执行。

c语言启动阶段分析

分析思路,抓主线分析,结合启动kernel时的log,进行分析。
1.开头做了一系列的初始化。
2.打印的第一个log,解压信息
在这里插入图片描述
通过搜索可知,该打印信息在Misc.c文件的decompress_kernel()函数中,这个就kernel的自解压代码。
在这里插入图片描述

3.setup_arch(&command_line)分析
在这里插入图片描述
该函数主要做了CPU ID , 机器码,以及cmdline处理。

4.rest_init
在这里插入图片描述
前面做了一堆初始化,检查处理。直接跳过,来到最后rest_init函数。
该函数主要是开启了2个进程。也就是kernel起来后的前三个进程1、2。还有一个进程0(idle进程)有kernel内部自己启动。
在这里插入图片描述
进程1:kernel_init函数就是进程1,这个进程被称为init进程。
进程2:kthreadd函数就是进程2,这个进程是linux内核的守护进程。这个进程是用来保证linux内核自己本身能正常工作的。

5.Init 进程分析
init进程刚开始运行的时候是内核态,它属于一个内核线程,然后他自己运行了一个用户态下面的程序后把自己强行转成了用户态。因为init进程自身完成了从内核态到用户态的过度,因此后续的其他进程都可以工作在用户态下面了,这个过程是单向的,后续想回到内核态只能通过调用相关的API实现。
在这里插入图片描述
(1)init进程中主要做了哪些事情:
(2)打开/dev/console
(3)复制了两个文件描述符
(4)挂载根文件系统
(5)调用init_post()去执行init进程
在这里插入图片描述
至此,Kernel启动完毕。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值