LINUX系统启动过程

本文旨在描述linux系统的整体启动流程,便于后续学习。并未深入去探究源码。

uboot(bootloader)

首先呢linux启动的过程就是由引导程序uboot的连接脚本arch/arm/cpu/u-boot.lds。进入uboot的启动,uboot的最终目的就是启动内核。uboot的引导启动分为两个部分(一般都是2部分)

第一阶段:初始化一些硬件,一般这个是汇编文件。主要代码在cpu/arm/start.s

第二阶段:初始化基础的硬件(时钟系统,或者串口之类的)准备SDRAM等,这个一般就是C文件了。最后会转进start_kernel.c去启动内核。

kernel

启动内核大概也可以分为两个阶段,

第一阶段:

  1. stage1就是内核解压完成并出现Uncompressing Linux...done,booting the kernel.之后的阶段。该部分代码实现在arch/arm/kernel的 head.S中,该文件中的汇编代码通过查找处理器内核类型和机器码类型调用相应的初始化函数,再建 立页表,最后跳转到start_kernel()函数开始内核的初始化工作。
  2. 为kernel_start.c的启动准备常规工作。

第二阶段:初始化内核的全部工作,主要是就是start_kernel。Linux内核启动的第二阶段从start_kernel函数开始。start_kernel是所有Linux平台进入系统内核初始化后的入口函数,它主要完成剩余的与 硬件平台相关的初始化工作,在进行一系列与内核相关的初始化后,调用第一个用户进程——init 进程并等待用户进程的执行,这样整个 Linux内核便启动完毕。函数位于init/main.c文件中。

总结:Linux系统启动,从start_kernel开始执行,中间执行一系列的初始化动作,为后面系统启动开始运行作准备。start_kernel函数的最后会调用rest_init,  然后在rest_init里创建一个进程去寻找文件系统中init程序并执行,这个就是系统的1号进程。

文件系统:Linux内核启动的最后一个目标第一个进程init,但必须以根文件系统为载体,所以在启动init之前,还要挂载根文件系统。init程序需要读取配置文件/etc/inittab。inittab是一个不可执行的文本文件,它有若干行指令所组成。在挂载文件系统时内核调用initrd(小型内存文件系统,五脏俱全,是一个微型linux),通过initrd,以只读方式挂载根文件系统。当根文件系统被挂载后,就会读取并运行/sbin/init来进行初始化工作。按次序依次执行/rc/sysinit ,这个时候会重新以读写的方式挂载根文件系统读取/etc/rc.d/rcN.d/来启动以s开头的服务,停止以k开头的服务。

根文件系统至少包括以下目录:

 /etc/:存储重要的配置文件。/bin/:存储常用且开机时必须用到的执行文件。/sbin/:存储着开机过程中所需的系统执行文件。/lib/:存储/bin/及/sbin/的执行文件所需的链接库,以及Linux的内核模块。/dev/:存储设备文件。

以只读的方式挂载根文件系统,之所以采用只读的方式挂载根文件系统是因为:此时Linux内核仍在启动阶段,还不是很稳定,如果采用可读可写的方式挂载根文件系统,万一Linux不小心宕机了,一来可能破坏根文件系统上的数据,再者Linux下次开机时得花上很长的时间来检查并修复根文件系统。

挂载根文件系统的而目的有两个:一是安装适当的内核模块,以便驱动某些硬件设备或启用某些功能;二是启动存储于文件系统中的init服务,以便让init服务接手后续的启动工作。执行init服务:Linux内核启动后的最后一个动作,就是从根文件系统上找出并执行init服务。Linux内核会依照下列的顺序寻找init服务:

1)/sbin/是否有init服务

2)/etc/是否有init服务

3)/bin/是否有init服务

4)如果都找不到最后执行/bin/sh

找到init服务后,Linux会让init服务负责后续初始化系统使用环境的工作,init启动后,就代表系统已经顺利地启动了linux内核。启动init服务时,init服务会读取/etc/inittab文件,根据/etc/inittab中的设置数据进行初始化系统环境的工作。/etc/inittab定义init服务在linux启动过程中必须依序执行以下几个Script:

( mips/X1000/system/etc/inittab的代码,可见这个配置文件会去启动rcS脚本)

 /etc/rc.d/rc.sysinit

 /etc/rc.d/rc

/etc/rc.d/rc.local

/etc/rc.d/rc.sysinit主要的功能是设置系统的基本环境,当init服务执行rc.sysinit时要完成一系列工作。(就是一堆杂活包括)

关于挂载文件系统:在rest_init(start_kernel的最后一个线程启动init进程)

        init进程在内核态下做了什么:重要的点就挂载根文件系统,并试图找到用户态下的那个init程序,原因是init进程要完成从内核态到用户态的转变就必须去运行一个用户态的应用程序,而内核源代码中的程序都是属于内核态的,所以这个应用程序必须不属于内核源代码,这样才能保证自己是用户态,所以这个应用程序就的是由另外一份文件提供,即根文件系统

挂载根文件系统,代码如下

if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {

ramdisk_execute_command = NULL;

prepare_namespace();

}

prepare_namespace函数中挂载根文件系统

根文件系统在哪里?根文件系统的文件系统类型是什么? uboot通过传参来告诉内核这些信息。uboot传参中的root=/dev/mmcblk0p2 rw 这一句就是告诉内核根文件系统在哪里uboot传参中的rootfstype=ext3这一句就是告诉内核rootfs的类型。

如果内核挂载根文件系统成功,则会打印出:VFS: Mounted root (ext3 filesystem) on device .如果挂载根文件系统失败,则会打印:No filesystem could mount root, tried:  yaffs2

  如果内核启动时挂载rootfs失败,则后面肯定没法执行了。内核中设置了启动失败休息5s自动重启的机制,因此这里会自动重启,所以有时候大家会看到反复重启的情况。

  如果挂载rootfs失败,可能的原因有:最常见的错误就是uboot的bootargs设置不对。rootfs烧录失败(fastboot烧录不容易出错,以前是手工烧录很容易出错)rootfs本身制作失败的。(尤其是自己做的rootfs,或者别人给的第一次用)。由此挂载上根文件系统。

关于挂载文件系统的rest_init代码:

在执行到rcS(system/etc/init.d)的时候最下面43行有一句bin/vbar_start.sh &会去执行vbar_start.sh脚本, 

在这个vbar_start的中94行就是把我们生成的./vbar复制进/vgapp就是去执行我们的应用了。

这个vbar是vbar下面Makefile22行定义生成的TARGET。

总结一下:启动uboot的第一阶段初始化硬件,第二阶段准备串口,SDRAM等,启动内核。内核启动第一阶段准备相关硬件初始化,第二阶段进入start_kernel正式启动内核,初始化MMU,中断系统等。最后在reset_init,创建线程挂载文件系统并寻找init服务,启动init服务,进入inittab脚本。启动对应rcS,完成init进程。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值