U-Boot学习整理

U-Boot学习整理

近期工作涉及到U-Boot,为了全面认识U-Boot和方便后期回顾,现将自己所学总结记录成文档,其中参考博客已在结尾处注明。

1. 简介

U-Boot 是一个主要用于嵌入式系统的引导加载程序.
全称:Universal Boot Loader
类型:开放源码项目
特点:是一套在GNU通用公共许可证之下发布的自由软件, 遵循GNU条款。支持多种嵌入式操作系统内核。

2. 工作模式

U-Boot工作模式
启动加载模式
Bootloader将嵌入式操作系统从FLASH中加载SDRAM中运行
下载模式
通过通信手段将内核映像或根文件映像从PC机下载到目标板Flash中

3. 目录结构

目录结构说明
/archArchitecture specific files
/apiMachine/arch independent API for external apps
/boardBoard dependent files
/cmdU-Boot commands functions
/commonMisc architecture independent functions
/configsBoard default configuration files
/diskCode for disk drive partition handling
/docDocumentation (don’t expect too much)
/driversCommonly used device drivers
/dtsContains Makefile for building internal U-Boot fdt.
/examplesExample code for standalone applications, etc.
/fsFilesystem code (cramfs, ext2, jffs2, etc.)
/includeHeader Files
/libLibrary routines generic to all architectures
/LicensesVarious license files
/netNetworking code
/postPower On Self Test
/scriptsVarious build scripts and Makefiles
/testVarious unit test files
/toolsTools to build S-Record or U-Boot images, etc.

其中/arch有多种处理器架构文件

/arch 【Files generic to ARC architecture】
/arc 【Files generic to ARC architecture】
/arm 【Files generic to ARM architecture】
/m68k 【Files generic to m68k architecture】
/microblaze【Files generic to microblaze architecture】
/mips 【Files generic to MIPS architecture】
/nds32 【Files generic to NDS32 architecture】
/nios2 【Files generic to Altera NIOS2 architecture】
/openrisc 【Files generic to OpenRISC architecture】
/powerpc 【Files generic to PowerPC architecture】
/riscv 【Files generic to RISC-V architecture】
/sandbox 【Files generic to HW-independent “sandbox”】
/sh 【Files generic to SH architecture】
/x86: 【Files generic to x86 architectur】

4. 初始化流程

4.1 入口start.S

代码运行从依赖于特定CPU体系的start.S开始。
例如
arch/powerpc/cpu/mpc83xx/start.S
arch/mips/cpu/start.S
arch/arm/cpu/armv8/start.S (工作中遇到过)
等等。在start.S中会调用三个函数, lowlevel_init, board_init_f, board_init_r。

  • lowlevel_init
    :目的是执行到board_init_f, 不提供GD(‘global_data’), stack,BSS,不能设置SDRAM,不能使用串口。
  • board_init_f
    :目的是执行到board_init_r, 支持GD, RAM中有栈, 没有BSS, 所以不能使用全局/静态变量,只能使用栈变量和GD结构体.
  • board_init_r
    : 运行主程序,进入到main_loop。global_data, SDRAM, BSS全部初始化成功,可以使用全局/静态变量。

start.S 主要做了什么?

  1. 获取当前异常等级EL(exception level),配置中断向量、MMU、Endian、i/d Cache等。配置ARM的勘误表,具体可参考apply_core_errata函数。
  2. 跳转指令跳转到弱函数lowlevel_init。(不同CPU可以定义同名函数进行覆盖)
  3. 判断CPU主从核,主核进行配置,包括中断分组和接口优先级。
  4. 主核跳转到_main,从核等待主核唤醒进行EL切换。
    详细介绍请参考

start.S 跳转至arch/arm/lib/crt0_64.S _main

(crt0 - C-runtime startup Code for AArch64 U-Boot)
_main 做了什么?源代码注释中的流程

  1. 设置执行board_init_f的初始环境,此时只提供存放GD结构体的栈空间,GD初始化需要早于调用board_init_f。
  2. 调用board_init_f, 用于执行系统RAM做硬件准备。此时必须使用GD结构体存储后续启动阶段的数据。
  3. 设置board_init_f()在系统内存中分配的堆栈和GD中间环境,此时BSS 和非常量数据仍然不可用。
  4. non-SPL, 调用relocate_code()。
    SPL, board_init_f() 不调用relocate (返回crt0)。
  5. 设置调用board_init_r 环境。
  6. 调用board_init_r。

4.2 common/board_f.c & common/board_r.c

board_init_f 主要是调用initcall_run_list(init_sequence_f),执行init_sequence_f定义的初始化。
board_init_r主要是调用initcall_run_list(init_sequence_r),执行init_sequence_r定义的初始化。
其中init_sequence_r最后会调用run_main_loop。

static int run_main_loop(void)
{
……………………
	/* main_loop() can return to retry autoboot, if so just run it again */
	for (;;)
		main_loop();
	return 0;
}

common/main.c main_loop 流程

/* We come here after U-Boot is initialised and ready to process commands */
void main_loop(void)
{
	const char *s;

	bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");

	if (IS_ENABLED(CONFIG_VERSION_VARIABLE))
		env_set("ver", version_string);  /* set version variable */

	cli_init();

	if (IS_ENABLED(CONFIG_USE_PREBOOT))
		run_preboot_environment_command();

	if (IS_ENABLED(CONFIG_UPDATE_TFTP))
		update_tftp(0UL, NULL, NULL);

	s = bootdelay_process();
	if (cli_process_fdt(&s))
		cli_secure_boot_cmd(s);

	autoboot_command(s);
	
	cli_loop();
} 

U-Boot 2020.04
Kernel 4.14.180
通过env_get获取环境变量值,然后通过函数run_command()执行。例如:
i)run_preboot_environment_command中env_get(“preboot”),然后执行相应命令。
ii)bootdelay_process中env_get(“bootdelay”),env_get(“bootcmd”),返回bootcmd值,然后通过run_command()函数来执行,至此,uboot启动结束,进入加载启动内核阶段,通过do_bootm来启动内核。

bootcmd中根据具体需求和版型,定制启动参数和命令。


[参考]
链接1: link
链接2: link
链接3: link

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值