嵌入式Linux启动过程

2019-07-12 17:53发布

今天看到了/etc/inittab,找了一通资料总结如下: 一般来说嵌入式Linux设备启动过程包括: 1、执行BootLoader 2、执行Kernel 3、执行应用程序 BootLoader的主要任务实际上是为了执行接下来的Kernel,它需要初始化最小系统(CPU+内存+Flash),为了调试信息初始化串口和显示屏。执行的最后阶段,将Kernel从Flash读取到RAM,验证+解压,送入参数,开始Kernel的引导了。
Kernel的主要任务是启动所有的外设,为执行应用程序准备。引导分为两步: A:start_kernel,建立核心环境。 一般包括:CPU,Memory, RTC, CACHE,串口设备的初始化,最终会得到第一个核心线程Init。 整个工作在start_kernel()函数中实现,具体工作包括: 打印Linux版本信息(printk(linux_banner)) 设置与体系结构相关的信息(setup_arch()) 页表结构初始化(paging_init()) 使用"arch/alpah/kernel/entry.S"的入口点设置系统的自陷入口(trap_init()) 使用alpha_mv结构和entry.S入口初始化系统IRQ(init_IRQ()) 核心进程调度器初始化(包括初始化几个缺省的Bottom-half, sched_init()) 时间, 定时器初始化(包括读取CMOS时钟,估测主频,初始化定时器中断等,time_init()) 提取并分析核心启动参数(从环境变量中读取参数,设置相应标志位等待处理,parse_options()) 控制台初始化(为输出信息而优先PCI初始化,console_init()) 剖析器数据结构初始化(prof_buffer和prof_len变量) 核心Cache初始化(描述Cahce信息的Cache,kemem_cache_init()) 延迟校准(获得始终jiffies与CPU主频ticks的延迟,calibrate_delay()) 内存初始化(社会子内存上下界和页表项初始值,mem_init()) 创建和设置内部及通用cache(“slab_cache”,kmem_cache_sizes_init()) 创建uid_taskcount SLAB cache(“uid_cache",uidcache_init()) 创建文件cache(”files_cache",filescache_init()) 创建目录cache(“dentry_cache",dcache_init()) 创建与虚拟内存相关的cache(“vm_area_struct”,”mm_struct“,vam_init())
块设备读取缓冲区初始化(同时创建”buffer_head"cache用户加速访问,buffer_init()) 创建页cache(内存页hash表初始化page_cache_init()) 创建信号队列cache(“signal_queue",signals_init()) 创建内存inode表(inode_init()) 创建内存文件描述符表(”filp_cache“,file_table_init()) 检查体系结构漏洞(check_bugs()) SMP机器其余CPU(除当前引导CPU)初始化(对于没有配置SMP的内核,此函数为空,smp_init()) 启动init过程(创建第一个核心线程,调用init())函数,原执行序列调用cpu_idle())等待调度,init())
第二部分(init()函数执行) 锁定内核(SMP) do_basic_setup() 完成外设及驱动程序的加载和初始化: 总线初始化(例如pci_init()) 网络初始化(sk_init(),skb_init() proto_init()) 创建bdflush核心线程(常驻核心空间,核心唤醒,用于清理被写过的内存缓冲区) 创建kupdate核心线程(常驻核心空间,定时执行,用于将缓冲区的信息更新到磁盘中) 启动核心调页线程kswapd 创建keventd(时间管理核心线程) 设备初始化(并口parport_init(),字符设备chr_dev_init(),块设备blk_dev_init(),SCSI设备scsi_dev_init(),网络设备net_dev_init(),磁盘初始化及分区检查,device_setup()) 执行文件格式设置(binfmt_setup()) 启动所有__initcall表示的函数(方便核心开发者添加启动函数,do_initcalls()) 文件系统初始化(filesystem_setup()) 安装root文件系统(mount_root()) 释放启动内存段(free_initmem())并解锁内核。 打开/dev/console设备,重定向stdin,stdout,stderr到控制台 搜索文件系统中的init程序(或者由init=命令行参数指定的程序),并使用execve()系统调用家挨执行init程序

Init进程执行过程
init进程是所有进程的起点,它读取/etc/inittab文件作为其行为指针,inittab文件每行格式: id:runlevel:action:process id:标识符 runlevel:运行级别。0-6及S或者s。0:系统关闭,1:重启至单用户模式,6:重启;S或者s表示单用户。 3:最常用级别,表示多用户模式
对于用户登录登录来说,整个过程包括: 打开终端,设置模式 输出登录界面和提示,接受用户名的输入(缺省的登录提示在/etc/issue文件中,远程登录提示在/etc/issue.net中) 以该用户名作为login的参数,加载login程序。 (如果用户名不是root,且存在/etc/nologin文件,login将输出nologin文件的内容,然后退出,这通常是用来系统维护时防止非root用户登录) (只有在/etc/securetty中登记的终端才允许root用户登录,若不存在,可以在任何终端中登录) 当用户登录检查后,login将搜索/etc/passwd文件(可能还会搜索/etc/shadow文件)比对密码,设置主目录和加载shell 执行shell并登录shell (执行/etc/profile) (~/.bash_profile) (~/.bash_login) (~/.profile) (~/.bashrc)

至此,系统中运行着init进程和由rc启动脚本激活的守护进程(如inetd等),运行着一个bash作为用户的命令解释器