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

君正T31学习(7)- 启动流程

一、简介

        前面几篇文章大概介绍了T31的系统分区和各个分区的作用,本章就详细介绍一下T31的启动流程,方便了解后续的应用开发。

分区偏移地址大小
uboot00x40000(256K)
tag0x400000x58000(352K)
kernel0x980000x500000(5120K = 5M)
rootfs0x5980000x300000(3072K = 3M)
recovery0x8980000x280000(2560K = 2.5M)
system0xb180000x468000(4512K)
  • uboot分区是启动的 “起点”,决定后续所有阶段能否执行。
  • tag分区是 U-Boot 与内核的 “通信桥梁”,确保内核获得正确的启动参数。
  • kenel分区是系统的 “骨架”,提供硬件管理和进程调度能力。
  • system分区是用户空间的 “基础”,存放系统运行必需的程序和配置。
  • rootfs分区是数据的 “仓库”,负责持久化存储动态数据。

二、启动流程

       1.硬件上电与 Boot ROM 加载 U-Boot(依赖 uboot分区

        上电复位

        当芯片接通电源后,硬件复位电路触发复位信号,CPU从复位向量地址(MIPS架构通常为0xBFC00000)开始执行第一条指令

        Boot ROM 程序执行

        复位向量指向芯片内部只读Boot ROM(固化在芯片中的固件),其功能是:

        1).初始化最基础的硬件(如内部SRAM、时钟振荡器)

        2).检测外部启动介质(根据硬件引脚配置,如BOOT_SEL引脚电平,判断从SPI_FLASH、NANO Flash或TF卡启动)。

        3).Boot ROM从uboot分区(Flash起始地址)读取u-boot镜像(含SPL“secondary program loader”阶段代码)到内部SRAM,跳转到u-boot入口。

      2.U-Boot 初始化与参数准备(依赖 uboot分区tag分区

        SPL 是精简的启动程序(通常存储在 Flash 起始地址),功能是为加载完整 Bootloader 做准备

        U-Boot 分两个阶段执行(SPL full U-Boot),核心任务是为加载内核做准备

        SPL 阶段

        初始化关键硬件:配置 PLL 时钟(提升 CPU 主频)、初始化 DDR 内存(使外部内存可用)。

        加载 full U-Boot:从uboot分区读取完整 U-Boot 镜像到 DDR 内存,跳转到 full U-Boot 执行。

        full U-Boot 阶段

        扩展硬件初始化:初始化 SPI 控制器(访问 Flash)、UART(串口调试)、网口(可选)。

        读取启动参数:从tag分区读取预设参数(如内核启动命令bootargs、硬件配置信息),或使用 U-Boot 环境变量(存储在uboot-env分区,非必需)。

        准备内核启动参数:将bootargs(如console=ttyS0,115200 root=/dev/mtdblock3)写入DDR内存的指定地址(供内核读取),若tag分区存在,参数优先从该分区加载。

        3.加载内核并启动(依赖kernel分区、tag分区)

        读取内核镜像

        U-Boot 根据bootcmd命令,从kernel分区读取内核镜像(如uImage),加载到 DDR 内存的指定地址

        传递启动参数

        U-Boot将tag分区中的参数或环境变量bootargs打包成内核可识别的格式(如MIPS架构的ATAGS),存储在内存中(通常位于内核镜像地址附近)。

        启动内核

        执行bootm或bootz命令,将CPU控制权交给内核,启动linux内核

        4.内核初始化与挂载根文件系统(依赖kernel分区、system分区、rootfs分区)

        内核启动后,从初始化硬件到进入用户空间,依赖多个分区

        内核解压与初始化

        内核镜像(如uImage)自动解压,执行架构相关初始化(禁用中断、设置页表、初始化进程调度器)

        解析 U-Boot 传递的bootargs参数,确定根文件系统位置

       驱动初始化与分区识别

        初始化 Flash 控制器驱动,识别所有 MTD 分区(包括system、rootfs分区),生成设备节点

       挂载根文件系统(rootfs)

        首先挂载system分区:该分区通常为只读文件系统(如 SquashFS),包含系统核心程序(/sbin/init、库文件、配置脚本)

        若存在 rootfs 分区(可读写,如 JFFS2/UBIFS),内核会将其挂载到 /mnt/data 或通过 overlayfs 与 system 分区合并,实现 “只读系统 + 读写数据” 的混合模式。

        5.用户空间初始化(依赖system分区、rootfs分区)

        内核启动用户空间第一个进程 init(位于 system 分区 的 /sbin/init)后,进入应用启动流程

        执行启动脚本

        init 进程解析 system 分区 中的 /etc/inittab 或 /etc/init.d/ 脚本,启动系统服务(如日志服务、网络配置)

        挂载其他分区

        执行 mount -a 挂载 rootfs 分区 到指定目录(如 /data),供应用程序存储用户数据、日志文件

        启动业务程序

        启动 T31 核心应用(如摄像头采集、视频编码、网络推流),程序运行中产生的动态数据写入 rootfs 分区,确保系统重启后数据不丢失

三、应用程序启动

        如果是针对应用层程序的开发,那么需要了解程序如何跑到应用层。

        从第二章可以知道,在kernel中,会挂载roofs。而rootf是根文件系统,所有的应用程序也都是从这里开始启动。系统跑的第一个进程为Init进程(/sbin/init)

        /sbin/init是Linux系统启动后的第一个用户态进程(PID=1),内核启动完成后会主动查找并执行它,后续由它负责初始化系统(如挂载分区、启动服务、初始化终端等)。

        由于内核本身不包含用户态程序/sbin/init必须在系统构建阶段就提前编译好并放入根文件系统,否则内核启动后会因找不到init而报错

        那么我们就需要了解init进程干了什么。

        inittab

        inittab文件在“SDK/os/rootfs/<4.7.2>/camera/rootfs_camera/etc”目录下。inittab是init进程的核心配置文件,定义了init启动后需要执行的动作、运行级别以及对应的处理逻辑。其作用是告诉Init“系统启动后该做什么,不同运行级别下该启动哪些程序”

        可以看到系统启动的第一个动作就是mount -a。该指令会自动挂载/ertc/fstab中定义的分区

        然后系统指向了/etc/init.d/rcS脚本

        该脚本负责挂载分区配置网络等基础工作。

        接下来执行“console::respawn:/sbin/getty -L console 115200 vt100”

        该指令设置,若串口终端退出,init会自动重启它确保终端始终可用

        最后执行“::shutdown:/bin/umount -a -r”。关机时自动撤销挂载相关分区。

        rcS

        rcS是Init进程在系统启动阶段执行的主初始化脚本,通常由inittab中的sysinit动作调用。它的作用是串联执行init.d目录中的启动脚本,完成系统初始化

        如果希望某个应用在上电后就启动,可以在该文件中添加命令来自启动,例如:

# 启动核心应用程序(如 T31 的摄像头服务)
/mnt/app/camera_main &

        rcS是系统初始化的“总调度员”,负责

        挂载文件系统(如rootfs之外的data分区)

        按顺序启动init.d中的所有服务脚本(嵌入式Linux通常只有rcS一个文件

        启动最终的业务程序(如T31的摄像头采集、编码服务)。

        总结一下:

        内核启动后执行/sbin/init进程,init进程读取/etc/initab,发现“::sysinit:/etc/init.d/rcS”,于是执行rcS脚本。rcS脚本挂载fstab中定义的分区,启动业务应用(如摄像头程序)

        

http://www.xdnf.cn/news/1452817.html

相关文章:

  • 当有鹿机器人读懂城市呼吸的韵律——具身智能如何重构户外清洁生态
  • 2025变现打法:AI+IP实现高效变现|创客匠人
  • 第十四届蓝桥杯青少组C++国赛[2023.5.28]第二部分编程题(4、 数独填数)
  • JS中正则表达式的运用
  • android Thread线程—HandlerThread
  • 汽车v型推力杆总成三维5自由度性能及疲劳测试系统
  • 追觅科技举办2025「敢梦敢为」发布会,发布超30款全场景重磅新品
  • 【iOS】 懒加载
  • 每日工作计划管理工具:核心功能详解
  • 《Java餐厅的待客之道:BIO, NIO, AIO三种服务模式的进化》
  • UE5 制作游戏框架的部分经验积累(持续更新)
  • Mybatis入门、操作数据、配置xml映射、数据封装
  • 深入探讨AI三大领域的核心技术、实践方法以及未来发展趋势,结合具体代码示例、流程图和Prompt工程实践,全面展示AI编程的强大能力。
  • leetcode21.合并两个有序链表
  • 来自AI的背包系统
  • solar应急响应-7月
  • 怎样让外网计算机访问局域网计算机?通过公网地址访问不同内网服务的设置方法
  • Web 与 Nginx 网站服务介绍与nginx安装
  • 泛型-泛型方法
  • C++工程实战入门笔记10-面向对象之静态成员变量和成员函数、构造函数和析构函数
  • 【C++设计模式】第二篇:策略模式(Strategy)--从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析
  • 联软科技:以“韧性安全”守护数字世界,致敬抗战胜利80周年的坚韧精神
  • vite与webpack对比
  • ATT层MTU大小
  • 【工具变量】数林指数数据集(2017-2024年)
  • 力扣654:最大二叉树
  • 51单片机-按键、蜂鸣器、定时器模块及中断
  • 大文件断点续传解决方案:基于Vue 2与Spring Boot的完整实现
  • C++并发编程-23. 线程间切分任务的方法
  • `void 0` 与 `undefined` 深度解析