You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

嵌入式系统Linux内核初始化里程碑规划及设备树处理时机问询

嵌入式Linux内核初始化里程碑路线图(修正&补充版)

嘿,我来帮你把这个流程理清楚,先修正你原来梳理里的小细节,再重点拆解设备树的处理时机:


完整初始化里程碑

  1. Bootloader 前置阶段

    • Bootloader(比如U-Boot)先完成基础硬件初始化(串口、RAM、时钟等),把内核镜像、**设备树Blob(DTB)**一起加载到RAM的指定地址,然后跳转到内核的入口地址启动内核。
  2. 内核汇编启动(head.o)

    • 内核首先进入和架构强绑定的汇编代码(比如ARM平台的head.S),完成最底层的初始化:
      • 设置内核栈、禁用全局中断
      • 识别当前CPU的架构/型号,配置核心寄存器
      • 启动MMU(这一步是在汇编阶段完成的,开启后才会进入C语言环境的start_kernel(),你原来的顺序没问题,但要明确阶段)
      • 最后跳转到C语言的核心入口start_kernel()
  3. 内核核心初始化(start_kernel())

    • 这是整个内核初始化的主入口,会依次初始化全局核心组件:
      • 初始化调度器、内存管理系统、printk打印框架等基础核心
      • 调用setup_arch()——这就是设备树处理的关键节点!
        • setup_arch()中,内核会从Bootloader传递的地址读取DTB文件,完成设备树的解析工作:把二进制的DTB转换成内核内部可操作的device_node结构体树
        • 同时setup_arch()还会依赖设备树提供的硬件信息,完成CPU架构相关的其他初始化(比如系统内存布局、总线架构的初始化)
      • 加载内核核心子系统框架(比如PCI总线、字符/块设备框架等)
  4. 驱动与模块初始化(do_initcalls())

    • 内核调用do_initcalls(),按优先级依次执行所有带*_initcall()标记的初始化函数(module_init()本质是封装成device_initcall级别的调用)
    • 这里是设备树节点被具体使用的阶段:各个驱动在初始化时,会通过of_match_table匹配设备树中的对应节点,读取节点里的硬件参数(比如寄存器基地址、中断号、时钟频率),完成设备的实例化和初始化
  5. 进入用户空间

    • 内核完成所有初始化后,通过kernel_init()启动用户空间的第一个进程:通常是/sbin/init,也可能是systemdbusybox init等替代程序

设备树处理时机的核心总结

针对你的疑问,这里明确两个关键阶段:

  • 设备树的解析(从DTB到内核内部结构):在setup_arch()中完成,这一步远早于do_initcalls()
  • 设备树节点的实际使用(驱动匹配、参数读取):在do_initcalls()阶段,由各个驱动的初始化函数分别处理

对你原梳理内容的小修正

  1. 启动MMU的时机:是在head.o的汇编代码阶段,而非进入start_kernel()之后(start_kernel()是MMU开启后才进入的C语言环境)
  2. 设备树的加载和解析是setup_arch()的核心工作之一,并不是在do_initcalls()阶段才开始的
  3. do_initcalls()是按优先级执行初始化函数的,module_init()对应的是device_initcall优先级,会在核心子系统初始化完成后执行

内容的提问来源于stack exchange,提问作者mozcelikors

火山引擎 最新活动