一 环境搭建
二 启动流程
1. u-boot 启动到 main_loop
-
启动流程特别说明:gd 的意义、用途
-
启动流程特别说明:init_sequence_r
-
启动流程特别说明:u-boot relocate 技术
2. u-boot-spl 启动到 u-boot
-
为什么需要SPL?
SPL 技术在产品设计中是可选的,当sram的存储不足以容纳u-boot的时候推荐使用。
思考问题:sram 较小的情况下,为什么不直接使用dram呢:bootrom直接把 u-boot加载到dram不就可以了吗?这样多好,中间环节spl就省略了。
笔者看来,问题可能出在bootrom 不支持dram的最优初始化参数,甚至不清楚如何初始化dram。这部分工作只能交给u-boot-spl、u-boot来做。 -
一个支持SPL技术的平台:DM814*
3.1 dm184x 应用了SPL技术(TI 把二进制spl文件命名为MLO)export ARCH=arm export CROSS_COMPILE=arm-linux-gnueabi- make ti814x_evm_defconfig make "CFLAGS+= -g OPTFLAGS= -Os" -j4| tee log
3.2 MLO 和 u-boot.img 在二进制大小的差异
ospin@ospin-VirtualBox:~/code/ti814x_boot$ ls -l MLO -rw-rw-r-- 1 ospin ospin 49436 2月 5 16:06 MLO ospin@ospin-VirtualBox:~/code/ti814x_boot$ ls -l u-boot.img -rw-rw-r-- 1 ospin ospin 390840 2月 5 16:06 u-boot.img
-
u-boot-spl 和 u-boot 在职能和源码组成上的差异?
4.1 MLO 和 u-boot 在二进制文件的差异
3. u-boot 加载内核以及ramdisk
-
内核:一般内核镜像的格式分类
-
ramdisk:ramdisk制作方法
-
u-boot 如何引导内核
4.1 引导Legacy Imagebootm, bootz, booti 这几个都是从内存中的某个地址获得kernel image。 bootz是启动zImage,而bootm和booti是启动uImage,其中booti专门用来启动ARM64的kernel image。 它们的基本语法是:bootX <kernel address> <rootdisk address> <fdt(dts file) address>,这里的address都是指内存的物理地址,需要提前把image和file加载到内存中,其中根文件系统的地址可以省略(包含在kernel image中),用-来代替。 在常规的启动引导过程中,uboot的各种启动方式实际上最后都是调用bootz的,但之前会设置很多环境变量作为启动的参数。在调试过程中,我们也同样可以手动设置好参数,直接用bootX系列来启动系统。
4.2 引导FIT Image
bootm
3. U-boot SPL 功能分析
-
SPL 和 非SPL U-boot 在二进制文件上的差异
3.4 SPL(对于TI:MLO),是可以编译dtb的,命名为:u-boot-spl.dtb,它怎么得到的呢?
/tools/fdtgrep -b u-boot,dm-pre-reloc -b u-boot,dm-spl -RT arch/arm/dts/origin-dtb-name.dtb -n /chosen -n /config -O dtb | ./tools/fdtgrep -r -O dtb - -o dts/dt-spl.dtb
可见u-boot-spl.dtb 是从origin-dtb-name.dtb 通过fdtgrep 过滤得到:
spl设备树只取带有{u-boot,dm-pre-reloc/u-boot,dm-spl 标记|| /chosen//config Node} 的节点,并且最终spl-dtb文件中的u-boot,dm-pre-reloc/u-boot,dm-spl 属性被去掉了。3.5
三 功能分析
1. 源码特点:平台抽象
u-boot 依赖Kconfig 完成特定代码的编译工作,依赖链接脚本完成代码链接工作。
链接好的代码又存在一层抽象,即:arm common level 代码形成模板调用接口,接口具体由cpu/board level代码实现。
-
Arm-Soc 平台代码:mach-xx
ospin@ospin-VirtualBox:~/code/u-boot-2018.11$ ls arch/arm/ config.mk Kconfig mach-at91 mach-exynos mach-k3 mach-mvebu mach-qemu mach-snapdragon mach-stm32mp mach-versal Makefile cpu Kconfig.debug mach-bcm283x mach-highbank mach-keystone mach-omap2 mach-rmobile mach-socfpga mach-sunxi mach-versatile thumb1 dts lib mach-bcmstb mach-imx mach-kirkwood mach-orion5x mach-rockchip mach-sti mach-tegra mach-zynq include mach-aspeed mach-davinci mach-integrator mach-meson mach-owl mach-s5pc1xx mach-stm32 mach-uniphier mach-zynqmp-r5
-
Cpu-Core 平台代码
arm产品系列 + 特别说明 cpu core 架构源码列表如下:ospin@ospin-VirtualBox:~/code/u-boot-2018.11$ ls arch/arm/cpu/ arm11 arm1136 arm1176 arm720t arm920t arm926ejs arm946es armv7 armv7m armv8 built-in.o Makefile pxa sa1100 u-boot.lds u-boot-spl.lds
#禁止FIQ, IRQ中断,重设异常向量表,进入svc Mode /home/ospin/code/u-boot-2018.11/arch/arm/cpu/armv7/start.S
-
Board 平台代码
lowlevel_init 存储在板级代码里/*_start 阶段板级平台代码*/ /home/ospin/code/u-boot-2018.11/board/armltd/vexpress/vexpress_common.c
CONFIG_SYS_INIT_SP_ADDR /*_start 阶段gd 的地址*/
-
Arm-common代码
4.1 Arm 中断向量表模板/home/ospin/code/u-boot-2018.11/arch/arm/lib/vectors.S #中断向量_start 存储在平台代码里 /home/ospin/code/u-boot-2018.11/arch/arm/cpu/armv7/start.S
4.2 Arm 初始化模板
/home/ospin/code/u-boot-2018.11/arch/arm/lib/crt0.S /* #arm 初始化模板 sram alloc board_init_f relocate_code relocate_vectors init relocated bss board_init_r */
-
All-arch common 模板
/*初始化通用模板*/ /home/ospin/code/u-boot-2018.11/common/board_f.c
2. DM 技术
- 参考博客
DM 技术是对driver 的上层封装/抽象。 比如serial-uclass 或者gpio-uclass, 用户可以选择支持他们,也可以不支持。 - 优点:
通过DM 技术, 用户可以把全部的平台设备和驱动程序bind 到 uclass 结构中,进行统一管理。
3. device_probe
- device_probe 设计的初衷:
笔者认为主要是完成硬件层面的配置。当然也可以用来完成driver 数据结构的组织工作。 - device_probe 什么时候调用?
上层通过uclass层准备获取设备的时候,可能调用下面两个函数。最终调用了uclass_get_device_tail 并在这个函数里完成device_probe.
意义:用户在准备使用设备时才probe!int uclass_get_device_by_name(enum uclass_id id, const char *name, struct udevice **devp) int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
4. 板级配置:.config 和 config.h
4.1 .config
- .config 借助Kconfig 语法生成,参考link
- .config 的意义
.config 决定了哪些源码文件被编译,以及源码文件中哪些预处理代码并编译。就好像从u-boot 的整体集合中选中了一个子集,支持自己的板子。 - .config 文件的输出
3.1 编译过程中,.config 文件中的key=val pair 被转换为C风格的头文件,然后存储在 include/generated/autoconf.h
3.2 u-boot.cfg 文件记录了 .config 和 conifg.h 的最终结果!!!
4.2 config.h
- conifg.h 文件用于板子所用到的参数,比如地址信息等,例如:
./include/config.h includes ./include/configs/vexpress_ca9x4.h
2. env 加载和存储
3. serial 设备驱动、接口
5. u-boot-spl 引导 u-boot
5. U-boot 二进制输出命名规则
6. U-boot设备树功能分析
7. U-boot 增加一个命令
https://blog.csdn.net/zd845101500/article/details/104017849
8. U-boot 启动内核 bootcmd
9. 内存布局和检测
9.1 内存分类
SRAM 是 SOC 片内存储, 容量非常小。 在 init_sequence_f 阶段用于存储 struct global_data 结构体
SDRAM 是SOC 片外存储, 容量和体积大。 在init_sequence_f 阶段调用 dram_init 实现检测。
dram_init 函数由board level 代码实现,通过读写内存完成存储单元功能检测。
9.2 内存布局
gd->ram_base = CONFIG_SYS_SDRAM_BASE; //内存基地址
gd->ram_top = gd->ram_base + get_effective_memsize(); //内存顶部地址
... reserve memorys...
gd->relocaddr = gd->ram_top - reserveed mem - ;
gd->relocaddr -= gd->mon_len; //uboot 重放地址
gd->start_addr_sp = gd->relocaddr;
gd->start_addr_sp -= TOTAL_MALLOC_LEN;//malloc 内存分配
gd->start_addr_sp -= sizeof(bd_t);
gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t)); //board info 内存分配
gd->start_addr_sp -= sizeof(gd_t);
gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t)); //新的gd_t 在sdram的分配
gd->start_addr_sp -= gd->fdt_size;// fdt 内存分配
gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp); //最后得到栈顶
11. struct global_data
四 工程设计
1.
五 工具的使用
-
qemu 也能支持gdb调试
1.1 qemu 启动gdbserver
1.2 arm-linux-gdb 安装方法
1.3 u-boot 符号表支持gdb#qemu $qemu-system-arm -M vexpress-a9 -s -S -kernel u-boot #gdb $arm-linux-gnueabi-gdb $(gdb) target remote localhost:1234 $(gdb) bt
-
vexpress a9 学习资料
3.1 qemu 对 vexpress的介绍:mothter board + daughter card
3.2 Versatile Express 的一篇wiki
3.3 qemu退出方法 -
反汇编dtb
https://blog.csdn.net/xiezhi123456/article/details/82416165