<Linux>Linux内核启动分析(一)——head.S

    xiaoxiao2021-04-14  31

    之前我们说到u-boot的最终目的是将内核从flash中读出,并且启动内核。那么内核一旦开始启动之后,就没有u-boot什么事情了,控制权就交给了内核,那么先来明确一下内核要做的事情:运行用户程序,而要想运行用户程序,就得先挂接到文件系统上。下面分析内核的启动流程:

    head.S主要做的事情是处理u-boot传入的参数,具体如下:

    1、判断是否支持这个CPU

    2、判断是否支持这个单板(对比机器ID)

    3、建立一级页表

    4、使能MMU

    5、跳到start_kernel函数

    下面具体分析这个流程:

    这是在内核文件下arch\arm\kernel目录下的head.S文件,也是内核启动的第一个文件。

    79行,通过设置CPSR寄存器来确保处理器进入管理模式,并且禁止中断。

    81行,通过读取CP15寄存器C0获得CPUid 

    82调用__lookup_processor_type这个函数确认内核是否支持当前CPU,如果支持,r5寄存器会返回一个用来描述这个处理器的结构体的地址,否则r5=0

    83行,先把这个r5的值保存到r10中

    85行,调用__lookup_machine_type这个函数确认内核是否支持当前开发板,如果支持,r5寄存器会返回一个用来描述这个开发板的结构体的地址,否则r5=0

    __lookup_processor_type和__lookup_machine_type这两个判断任何一个出现错误,内核都会停止启动,并且跳转到显示错误的函数如54、87

    而一旦两个判断都通过,那么就会执行88行,生成页表。

    下面主要来看一下__lookup_processor_type和__lookup_machine_type这个两个函数是如何具体实现的。

    147行,r3=178代码的物理地址

    148行,r5=__proc_info_beginr6=__proc_info_end,虚拟地址,r7=178行代码的虚地

    149行,物理地址和虚拟地址的差值

    150行,__proc_info_begin对应的物理地址

    151行,__proc_info_end对应的物理地址

    152行,r3r4=__proc_info_list结构中的cpu_valcpu_mask

    153行,r4=r4&r9=cpu_mask&传入的CPU ID

    154行,比较

    155行,如果相等,表示找到匹配的__proc_info_list结构,跳到160

    156行,r5指向下一个__proc_info_list结构

    157行,是否已经比较完所有的__proc_info_list结构?

    158行,没有则继续比较

    159行,比较完毕,但是没有匹配的__proc_info_list结构,r5=0

    160行,返回

    在启动mmu之前,使用的都是物理地址,而内核却是用虚拟地址连接的,所以在访问__proc_info_list结构之前,先将它的虚拟地址转换成物理地址,147~151代码实现

    r3=178行代码的物理地址

    R4=178行代码的虚拟地址,

    148行,r5=__arch_info_beginr6=__arch_info_end,虚拟地址,r4=178行代码的虚地

    149行,物理地址和虚拟地址的差值

    150行,__arch_info_begin对应的物理地址

    151行,__arch_info_end对应的物理地址

    152行,r5machine_desc结构地址

    153行,r4=r4&r9=cpu_mask&传入的CPU ID

    154行,比较

    155行,如果相等,表示找到匹配的__proc_info_list结构,跳到160

    156行,r5指向下一个__proc_info_list结构

    157行,是否已经比较完所有的__proc_info_list结构?

    158行,没有则继续比较

    159行,比较完毕,但是没有匹配的__proc_info_list结构,r5=0

    160行,返回

    当这个两个判断都满足的时候,建立页表,接着启动MMU我们可以看到下面的这条语句:

    97~99行,启动MMU之后会跳转到_swich_data这个函数,具体的代码就不一一分析了,不过可以跟踪流程如下:

    _swich_data——>__mmap_switched——>start_kernel其中最重要的是start_kernel这个函数,这是内核启动的第一个C语言函数。

    到这里可以先来总结一下head.S主要做的事情:

    1、通过分析u-boot启动流程,我们知道u-boot在启动内核之前,会吧一些参数传给内核(具体过程请参考u-boot启动流程的分析)。而这些传入的是机器ID和其他参数。在head.S中,就是利用u-boot传入的机器ID来判断内核是否支持这个CPU和这个开发板。

    2、如果1中的两个条件都满足,则会建立页表,并且启动MMU

    在这里简单介绍一下什么是MMU:

    MMU也就是memory management  uint,也就是内存管理单元。它负责虚拟地址到物理地址的映射,并且提供内存机制的内存访问权限检查。

    为什么要启动MMU?

    由于内核使用的是虚拟地址连接,所以启动MMU,更方便地实现虚拟地址到物理地址的映射。

    3、启动MMU之后,内核流程会跳转到start_kernel函数,在这个函数中将会处理u-boot传入的其他参数。

    下次接着分析

    转载请注明原文地址: https://ju.6miu.com/read-670108.html

    最新回复(0)