uboot和内核启动大致流程
bootloader 启动流程和功能说明
bootloader 基本功能说明
- 有的程序在启动bootloader之前会运行一段
固化程序
- bootloader 启动过程分单阶段和多阶段
- 多阶段可以提供更复杂的功能和更好的移植性
- 一般从固态存储设备启动分两个阶段
第一个阶段 bootloader 启动说明
源码 U-boot/arch/arm/cpu/xxx(armv7)/start.S
- 用汇编, 是因为机器刚开始就从某个内存地址开始取值操作, 这个时候内存没有初始化好, 汇编不需要堆栈
- 硬件设备初始化(关闭 看门口, 关中断, 设置CPU的速度和时钟频率, RAM初始化)
- 为加载第二阶段的 Bootloader 的代码准备 RAM 空间(初始化RAM芯片,使可用, 调用lowlevel_init使外接SDRAM可用)
- 复制 Bootloader 的第二阶段代码到 RAM 空间
- 设置好栈
- 跳转到第二阶段代码的入口 C 处
第二个阶段 bootloader 启动阶段
源码 start.S 中, 初始化相关硬件之后, 会跳转 _main
, 文件名: arch/arm/lib/crt0.S
- 初始化本阶段要使用的硬件设备(CPU中断, 系统时钟,定时器, 检查flash, 串口初始化, 检测系统内存映射)
- 检测系统内存映射
- 将内核映像和根文件系统映像从 flash 上读到 RAM 空间中
- 为内核设置启动参数
- 调用内核, 至少初始化串口用于调试
zynq 为例:
`crt0.S`:
->board_init_f
->ps7_init //初始化mio, pll(锁相环), clock, addr, peripherals(外围设备)
->arch_cpu_init //根据手册, 对APB, ROM 等寄存器初始化
->board_init_r //gpio, led, 时钟相关初始化, 加载环境变量,然后进入主循环
-> main_loop()
bootloader 和 内核交互
- 单向的交互
- bootloader 将各类参数传递给内核, 由于不能同时运行, 传递办法只有一个: 将参数放在某个约定的地方
- 然后再启动内核, 内核从约定的地方获取参数
- uboot 下使用
go + [内存地址]
可以运行指定内存中的编译后的程序
linux 镜像启动过程
- linux内核启动也是分为两个部分
- 架构/开发板相关的引导过程, 用汇编编写
arch/arm/kernel/head.S
, 内核启动执行的第一个文件- 连接内核时使用的虚拟地址, 所以要设置页表, 使能MMU
- 调用 C 函数
start_kernel
之前的常规工作, 包括复制数据段、清除BSS段、调用 start_kernel
- 后续的通用启动过程, C语言
init/main.c
中的start_kernel
- 内核初始化的全部工作
- 调用 rest_init 函数启动init过程, 创建系统第一个进程
setup_arch
函数用于对芯片架构/开发板相关的设置, 比如重新设置页表, 设置系统时钟, 初始化串口
- 架构/开发板相关的引导过程, 用汇编编写
根文件系统
根文件系统: 既创建各种目录, 并且在里面创建各种文件, 比如在 /bin
、/sbin
目录下存放各种可执行程序, 在/etc
目录下存放配置文件等等.
Busybox移植
Busybox
是一个遵循 GPL v2
协议的开源项目。Busybox
将众多的 UNIX 命令集合进一个很小的可执行程序中, 用来替换 GUN fileutils
和 shellutils
等工具集, 其体积小, 动态链接只有几百KB
, 静态链接也只有 1MB
左右
本文来自博客园踩坑狭,作者:韩若明瞳,转载请注明原文链接:https://www.cnblogs.com/han-guang-xue/p/17420921.html