uboot-启动程序脚本位置-init进程

  • UBoot作用:设备上电需要初始化硬件,但是不同设别区别较大,因此,设计UBoot实现管理开机初始化设备的功能

参考链接

示例

  • 在./project/image/putput/rootfs/bootconfig路径下有demo.sh,里面是启动时运行的各种指令程序
  • 此demo.sh,可能也是init进程启动后才执行的脚本

疑问是在哪里写了执行这个demo.sh的呢?

解答

  • 在编译镜像后,在project文件夹下有“./project/image/configs/i6b0/rootfs.mk:32: echo export PATH=$$PATH:/config >> ${OUTPUTDIR}/rootfs/etc/profile”

  • 打开rootfs.mk显示:
    '''
    echo export PATH=$$PATH:/config >> ${OUTPUTDIR}/rootfs/etc/profile
    '''

  • 继续打开profile后,显示代码:
    '''
    if [ -e /bootconfig/demo.sh ]; then
    /bootconfig/demo.sh
    fi;
    '''

  • 最后打开“./project/image/output/rootfs/bootconfig/demo.sh”可看到init进程运行后需要执行的程序命令

内核初始化

合成内核镜像

  • 1.二进制ELF内核主题vmlinux,先去除符号、标注等,成为二进制目标文件
  • 2.通过gzip压缩得到piggy.gz的压缩二进制内核文件
  • 3.通过asm汇编链接得到可启动的内核镜像

其镜像文件结构

  • 由顶层往下为:
  • piggy.o,msic.o(包含镜像解压的函数),big_endian.o(转为大端字节序程序),head-xscale.o(为XScale处理器初始化),head.o(启动代码,引导程序将控制权交给这个对象,其是汇编程序完成处理器初始化任务)

初始化的控制流

  • 系统上电后,存储在非易失存储介质flash和ROM上的引导加载程序会立刻获取处理区的控制权
  • 引导加载程序的作用是:底层初始化、硬件检查、镜像加载运行
  • 之后引导加载程序会将控制权交给启动加载程序的head.o,用以执行

内核入口head.o

  • 此文件是由head.S编译而来,主要作用是:
    • 1.初始化MMU内存
    • 2.初始化处理器架构
    • 3.初始化页表Page Table
    • 4.跳转到start_kernel()函数
  • start_kernel()函数位于./init/main.c文件中,main.c是负责内核启动的源文件,是内核开发主要的对象
  • start_kernel()函数会调用./arch/arm/kernel/setup.c文件函数用于设置架构相关

内核命令行处理

  • 1.在main.c->start_kernel()->setup_arch()中,会传入内核参数
    • 内核参数的处理需要__setup宏
  • 2.控制台初始化由./kernel/printk.c中的console_setup()函数完成,后续才是__setup宏的使用
  • 3.在./include/linux/init.h中,有__setup系列宏夫人定义,其内容为初始化数组,将内容转换为console=输出,在链接阶段会汇集到.init.setup段中
  • 4.内核字符串处理的函数,由./kernel/params.c的函数解析获得
  • 5.借鉴./kernel/params.c中parase_args()函数
  • 6.在文件./include/linux/moduleparam.h中,有module_param*系列函数

子系统初始化

  • 除了上述的初始化函数,还有用连接器构造一个函数指针列表,每个指针指向一个初始化函数,然后在循环中依次执行这些函数
  • 在./arch/arm/kernel中的static int __init customize_machine(void)可自定义添加设备初始化
  • 此过程使用了__init宏,并防止在vmlinux ELF的.init.text段中
  • 其他类似的函数initcall宏

init线程

  • 1.在./init/main.c赋予内核以生命后,函数start_kernel()函数执行一系列初始化函数,生成第一个内核进程init,其PID为1
  • 2.此时,系统引导有2个线程,一个是start_kernel(),另一个是init(),且前者会变成空闲进程
  • 3.start_kernel()会调用rest_init(),其中有kernel_thread()执行kernel_int()函数,创建init进程
  • 4.最后start_kernel()会调用rest_init()函数中的cpu_idle()后,该最后start_kernel线程进入死循环。因为start_kernel()函数很大,退出需要回收内存资源,所以进入等待状态,而会调用rest_init()函数(此函数运行在start_kernel线程上)占用资源少其变成系统的空闲进程
  • 5.最后通过init进程完成最后的初始化任务。通过initcalls、initcall_debug等实现
  • 6.最后的内核引导步骤:./kernel/main.c/init_post(),其作用是释放初始化函数和内存资源,打开系统控制台设备,启动第一个用户进程

用户空间初始化

  • 内核在main.c中会挂载文件系统,最后执行的指令就会执行各系统目录下的init进程/sbin/init
  • 这是一个软连接,会指向busybox,也就是内核执行的第一个用户进程
  • 系统配置项在目录/etc/inittab
  • 系统运行级别相关配置在/etc/rc.d

其他

  • ldd 用于库连接依赖
  • libc.so.6 : 标准C程序库
  • ld.so.1 :Linux动态加载器
  • 初始化RAM ,使用initrd进行引导,需要initrd的支持,linuxrc,initramfs

启动程序流程参考资料

posted @ 2023-07-03 10:36  starc再起航  阅读(129)  评论(0编辑  收藏  举报