当前位置: 首页 > news >正文

i.MX6ULL Linux内核启动流程深度解析

概述

i.MX6ULL作为NXP推出的高性能、低功耗的ARM Cortex-A7处理器,在嵌入式领域广泛应用。其Linux内核启动流程与x86架构有显著差异,主要依赖于芯片厂商提供的引导固件和设备树机制。本文将详细剖析i.MX6ULL的完整启动过程。

启动流程总览

i.MX6ULL的Linux内核启动可以分为五个主要阶段:

1. “Boot ROM阶段”- 芯片内置固件
2. "引导加载程序阶段" - U-Boot主导
3. "内核解压与重定位" - zImage处理
4. "内核主体初始化" - 汇编与C语言阶段
5. "用户空间初始化" - 系统服务启动

阶段一:Boot ROM - 芯片固化的起点

Boot ROM是i.MX6ULL上电后执行的第一段代码,由NXP固化在芯片内部ROM中,不可修改。

执行流程:

1. "上电复位"


   - 芯片加电,CPU从固定地址开始执行Boot ROM代码

2. "基础硬件初始化"


   - 初始化时钟、临时存储等最基本硬件组件

3. "引导设备选择"


   // Boot ROM根据BOOT_MODE[1:0]引脚电平决定启动源:
   // - 00: 从FUSE启动
   // - 01: 串行下载模式
   // - 10: SD/TF卡
   // - 11: eMMC/NAND Flash

4. "镜像加载与验证"


   - 从存储设备的固定位置(通常是第1KB偏移处)加载启动镜像
   - 镜像必须包含特定格式的头部:
     - "IVT (Image Vector Table)" - 程序入口地址表
     - "Boot Data" - 启动数据配置
     - "DCD (Device Configuration Data)" - 关键外设初始化配置

5. "DDR初始化"


   - DCD包含寄存器配置命令,用于初始化DDR3/LPDDR2等外部RAM
   - 这是关键步骤,因为U-Boot需要运行在外部RAM中

6. "控制权转移"


   - 验证通过后,跳转到IVT中指定的U-Boot入口地址

阶段二:U-Boot引导加载程序

        U-Boot是ARM嵌入式领域最主流的Bootloader,通常分为两个阶段。

U-Boot SPL (Secondary Program Loader)

SPL是一个精简的U-Boot,主要任务包括:
// SPL主要执行流程:
1. 初始化时钟系统
2. 初始化DDR控制器(可能复用或增强DCD配置)
3. 从存储设备加载完整U-Boot到DDR
4. 跳转到Full U-Boot执行

Full U-Boot (第二阶段)

完整版U-Boot运行在DDR中,执行更复杂的初始化:

1. "外设初始化"


   - 网卡、USB、串口等外设驱动加载

2. "环境变量解析"


   # 关键环境变量示例:
   bootcmd=mmc dev 0; fatload mmc 0:1 0x80800000 zImage; fatload mmc 0:1 0x83000000 imx6ull.dtb; bootz 0x80800000 - 0x83000000
   bootargs=console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw

3. "内核镜像加载"


   - 将压缩内核映像(zImage)加载到DDR指定地址(如0x80800000)
   - 将设备树Blob(.dtb)加载到另一地址(如0x83000000)
   - 可选:加载initramfs到内存

4. "启动参数准备"


   - 修改设备树或准备ATAG列表,传递系统信息:
     - 内存大小和布局
     - 内核命令行参数
     - 硬件配置信息

5. "内核启动"


   - 通过`bootz`或`bootm`命令跳转到zImage地址
   - 将设备树地址作为参数传递给内核

---

阶段三:内核解压与重定位

arch/arm/boot/compressed/head.S

这是压缩内核镜像(zImage)的入口点,执行环境:
- CPU模式:SVC
- MMU状态:关闭
- 缓存状态:关闭或未初始化

主要任务:

1. "基础核心设置"


   - 关闭中断,设置临时栈

2. "自解压过程"


   // 检查压缩格式(通常是gzip)
   // 在当前位置解压zImage
   // 将解压后的内核映像(Image)重定位到目标地址
   // 典型目标地址:0x80008000(前面保留32KB页表空间)

3. "参数传递准备"


   - 设置寄存器状态:
     - r0 = 0
     - r1 = ARM机器ID(现代内核中重要性降低)
     - r2 = 设备树Blob在RAM中的物理地址

4. "跳转到内核"


   - 调用`__enter_kernel`进入解压后的内核

阶段四:内核主体初始化

arch/arm/kernel/head.S

这是解压后内核的真正入口点,负责创建内核运行的完整环境。

核心工作流程:

1. "机器描述符匹配"


   // 现代内核基于设备树兼容性字符串匹配:
   // 设备树: compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
   // 内核查找匹配的struct machine_desc

2. "初始页表创建"


   - 建立1:1映射(虚拟地址=物理地址)的段映射
   - 仅映射内核代码所在的几MB空间,为开启MMU做准备

3. "MMU启用"


   - 通过设置协处理器寄存器开启MMU
   - 这是关键转折点,之后所有内存访问都经过MMU转换

4. "环境清理"


   - 执行绝对跳转清除处理器流水线
   - 设置栈指针,清零BSS段

5. "进入C语言世界"
   - 跳转到`start_kernel()`函数

 init/main.c → start_kernel()

这是所有Linux架构共享的初始化起点,对i.MX6ULL特别重要的调用包括:


void __init start_kernel(void)
{
    // 架构相关初始化
    setup_arch(&command_line);  // 解析设备树,初始化内存
    
    // 定时器系统初始化
    timer_init();               // 初始化i.MX6ULL系统定时器
    
    // 中断控制器初始化
    init_IRQ();                 // 初始化GIC(通用中断控制器)
    
    // 子系统初始化
    console_init();             // 控制台初始化
    rest_init();                // 创建第一个用户进程
}

在`setup_arch()`中:
- 解析设备树,获取内存布局信息
- 将物理内存信息添加到memblock分配器
- 识别系统硬件拓扑结构

阶段五:用户空间初始化

rest_init() → 用户空间的诞生

1. "核心进程创建"

   // 创建关键内核线程:
   kernel_thread(kernel_init, NULL, CLONE_FS);    // PID 1
   kernel_thread(kthreadd, NULL, CLONE_FS);       // PID 2
   ```

2. "驱动初始化 - do_initcalls()"


   - 按优先级顺序执行所有编译到内核中的初始化函数
   - i.MX6ULL外设驱动初始化序列:


     // 早期初始化
     pure_initcall()    // 最早期驱动
     core_initcall()    // 核心子系统
     
     // 外设驱动初始化
     postcore_initcall() // GPIO控制器、时钟框架
     arch_initcall()     // I2C、SPI控制器
     subsys_initcall()   // 网卡驱动(FEC)、MMC/SD控制器
     fs_initcall()       // 文件系统
     device_initcall()   // 其他设备驱动
     late_initcall()     // 最后期初始化

3. "根文件系统挂载"


   - 根据U-Boot传递的`root=`参数确定根文件系统位置
   - 常见配置:


     # SD卡根文件系统
     root=/dev/mmcblk1p2 rootwait rw
     
     # NFS根文件系统  
     root=/dev/nfs nfsroot=192.168.1.100:/nfsroot ip=dhcp

4. "用户空间启动"


   - 如果使用initramfs,执行其中的`/init`
   - 否则直接寻找并执行根文件系统中的`/sbin/init`
   - 最终启动systemd或busybox init等初始化系统

完整启动流程图


i.MX6ULL 上电复位
     |
     v
Boot ROM (芯片固件)
     | → 根据BOOT引脚选择启动设备
     | → 加载IVT、DCD和U-Boot SPL
     v
U-Boot SPL (精简引导)
     | → 初始化DDR内存
     | → 加载Full U-Boot到DDR
     v
U-Boot (完整引导)
     | → 初始化网卡、USB等外设
     | → 加载zImage和.dtb到指定地址
     | → 通过bootz跳转,传递参数
     v
内核解压 (head.S)
     | → 自解压zImage
     | → 重定位内核映像
     v
内核主体 (head.S)
     | → 匹配机器描述符
     | → 创建初始页表
     | → 开启MMU
     v
通用内核初始化 (start_kernel)
     | → 解析设备树,初始化内存
     | → 初始化中断、定时器
     | → 初始化i.MX6ULL外设驱动
     v
用户空间启动 (rest_init)
     | → 创建init进程(PID 1)
     | → 执行do_initcalls()初始化驱动
     | → 挂载根文件系统
     v
执行 /sbin/init (systemd/busybox)
     |
     v
系统完全就绪

关键特性总结

1. "Boot ROM依赖":ARM SoC特有的芯片固化启动代码
2. "DCD配置关键性":DDR初始化在Bootloader运行前完成
3. "设备树核心地位":完全替代x86的BIOS信息传递机制
4. "渐进式MMU启用":需要在汇编阶段手动创建初始页表
5. "驱动初始化层级化":通过initcall机制确保正确的初始化顺序

理解i.MX6ULL的完整启动流程,对于嵌入式Linux开发、系统调试和性能优化都具有重要意义。这种深入的理解能够帮助开发者更好地定位启动问题,优化启动时间,以及进行系统级定制开发。

http://www.dtcms.com/a/512329.html

相关文章:

  • Browser-Use 打造可操作浏览器的 AI 智能体
  • php网站开发入门到精通教程好玩的游戏网页
  • 代码仓库码云(gitee)配置环境记录
  • 织梦网站模板陶瓷广州建设行业网站
  • 面试(六)——Java IO 流
  • 怎么做视频网站教程php彩票网站建设教程
  • 大模型(Large Language Model, LLM)——什么是大模型,大模型的基本原理、架构、流程
  • 长春网站建设排名怎样用自己电脑做网站
  • 基于 Redis 的基数统计:高效的大规模去重与计数
  • 机械外贸网站站长网站工具
  • 广州企业建站素材安徽禹尧工程建设有限公司网站
  • MySQL if函数
  • Promise.all怎么用
  • 成都网站建设开发价玉环哪里有做网站
  • 01)mysql数据误删恢复相关-mysql5.7 开启 binlog、设置binlog 保留时间
  • 电力电子技术 第五章——非连续导电模式
  • Django 项目 .gitignore 模板
  • MySQL 中文排序(拼音排序)不生效问题全解析
  • 建站网络公司云南网站备案难吗
  • 深度学习(8)- PyTorch 数据处理与加载
  • JAVA:Spring Boot 集成 Jackson 实现高效 JSON 处理
  • 深度学习之YOLO系列YOLOv4
  • 江西移动网站建站推广外包
  • 张家口网站建设zjktao温州公司网址公司
  • Cef笔记:Cef消息循环的集成
  • 第十六篇:Lambda表达式:匿名函数对象的艺术
  • 织梦cms通用蓝白简介大气企业网站环保科技公司源码汕头网站制作全过程
  • xss-labs pass-06
  • 解决selenium提示chrome版本过低问题
  • 重庆做网站电话深圳做装修网站费用多少