00、uboot的宏观启动
第1种:bootROM读取SPL到片内RAM,SPL初始化DDR,SPL把uboot程序copy到DDR,uboot启动进行必要外设初始化、自我拷贝、重定位等。
第2种:bootROM直接读取uboot的头部信息(IVT、DCD)将DDR初始化完成,bootROM拷贝uboot程序到DDR,uboot开始执行。
uboot的启动设备有很多,由bootPin开关(类似于STM32的boot0和boot1引脚)决定bootROM从哪种设备启动(上电开始从哪种存储设备读取信息去执行)。
一、uboot的启动
- 设置CPSR寄存器,进入SVC模式,关闭中断irq、fiq;
- 设置SCTLR、VBAR寄存器,进行中断向量表重定位,向VBAR写入中断向量表的基地址0x87800000;
- 关闭MMU,关闭D-cache,cpu类型检查,进入__main开始板级初始化;
- 初始化内部定时器(类似于Cortex-M系列内核的滴答定时器);
- uboot拷贝自己到DDR高地址0x9FF47000处(产生地址偏移:0x9FF47000 - 0x87800000=0x18747000),让出空间给准备要加载的内核;
- uboot进行重定位,采用位置无关码(pc的相对偏移)访问Label,并且修改Label的内容:原Label内容+偏移0x18747000,这样就可以通过与pc的相对偏移访问到Label,取出Label的内容,也即取出真正要访问的函数或全局变量的地址(Label的内容=真正要访问的函数或全局变量的地址,可以通过反汇编去验证)。
- 再次重定位中断向量表重定位,向VBAR写入NEW中断向量表的基地址0x9FF47000;
- 初始化其他外设;
- uboot进入命令行模式等待或者直接尝试启动内核(bootz指令启动内核:主要传递内核镜像和设备树地址,如:bootz 80800000 - 83000000,内核地址0x80800000 ,设备树地址0x83000000);
二、kernel的启动
内核启动前的要求:MMU off、D-cache off、I-cache = don’t care、如果支持设备树内核需要知道设备树的首地址;
uboot要传递给内核的核心参数:bootargs(控制台参数、根文件系统位置等)、bootcmd(读取外部存储器的内核、设备树文件加载到DDR指定位置并启动);
从arch/arm/kernel/vmlinux.lds下ENTRY(stext)内核入口,stext在arch/arm/kernel/head.S下:
1)处理器继续处于SVC,关闭所有中断,“内核详细的启动工作...”
2)内核启动函数:start_kernel -> “一系列详细过程...”-> reset_init :
内部使用rcu锁调度器(区别读写锁,rcu读不会被写阻塞)
a. pid=1:init进程
init进程进行其他初始化工作:
-注册控制台设备“ /dev/console”,作为标准输入,同时复制此文件描述符,同时作为标准输出、标准错误;
-根据bootargs参数console(console=ttymxc0,115200)设置/dev/console对应的实际设备;
-根据bootargs参数root(root=/dev/mmcblk1p2)挂载根文件系统,也可以通过nfsroot挂载网络文件系统;
-根据bootargs参数init(init=/linuxrc),在根文件系统下查找init用户态进程/linuxrc,找不到,内核就会启动失败!
b. pid=2:负责内核进程调度和管理的进程;
c. pid=0:主进程演变为idle进程,相当于空闲任务;
---------------------------------------------------------------------------------------------