uboot学习笔记

前言

  • 这只是个人的一些经验,见解,有点杂,也难免有错误,欢迎指正;
  • uboot用的2016.01;
  • SOC以ARM920,S3C2410作为例子;

1 uboot启动过程

reset(CPU设为SVC模式,关闭看门狗,禁用所有中断,设置时钟分频)                 arch/arm/cpu/arm920t/start.S
    cpu_init_crit(关闭MMU和I/DCache)                                          arch/arm/cpu/arm920t/start.S
        lowlevel_init(初始化SDRAM)                                            board/samsung/smdk2410/lowlevel_init.S(注1)
    _main(设置栈指针,内存搬移,C环境初始化,部分硬件初始化等)                arch/arm/lib/crt0.S
        board_init_f_mem(给gd(注2)分配一段全零的内存)                       common/init/board_init.c

如果是SPL:
        board_init_f(注3)
        spl_relocate_stack_gd(重新设置栈指针)                                 common/spl/spl.c
        一堆汇编(清BSS区域)                                                   arch/arm/lib/crt0.S
        board_init_r(注4)

如果是uboot:
        board_init_f(执行init_sequence_f(注5)中的所有函数(注6))           common/board_f.c
        一堆汇编代码(重新设置栈指针,重新给gd分配空间)                        arch/arm/cpu/arm920t/start.S
        relocate_code(搬移uboot以及uboot的全局变量区到SDRAM)                  arch/arm/lib/relocate.S
        relocate_vectors(注7)(重定位中断向量表,好像是把0重定位到0xFFFF0000)arch/arm/lib/relocate.S
        c_runtime_cpu_setup                                                     arch/arm/cpu/arm920t/start.S
        一堆汇编(清BSS区域)                                                   arch/arm/lib/crt0.S
        coloured_LED_init                                                       弱定义函数,用户可以自定义
        red_led_on                                                              弱定义函数,用户可以自定义
        board_init_r(执行init_sequence_r中的所有函数(注8))                  common/board_r.c
注1:这个位置并不统一。有些在arch/arm/mach-XXX/lowlevel_init.S,有些在arch/arm/cpu/.../lowlevel_init.S
注2:gd就是global-data的意思,它的定义是:register gd_t *gd asm ("r13")。用来存储uboot在前期启动时用到的全局变量。
        它刚开始使用了R13这个寄存器(也就是栈指针寄存器)作为自己的地址,但是后面它会被分配到内存控制中去。
注3:
	board_init_f这个函数的定义是这样的:
		#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
			使用SPL提供的弱定义,这个函数会跳转到board_init_r					arch/arm/lib/spl.c(用户可以自定义)
		#else
			使用uboot提供的定义													common/board_f.c
		#endif
	这个函数的作用:做一些必要的初始化,为board_init_r做准备,不同的SOC驱动各不相同
注4:
	board_init_r这个函数的定义是这样的:
		#ifdef CONFIG_SPL_BUILD
			#ifdef CONFIG_SPL_FRAMEWORK
				使用uboot自带的board_init_r,位于common/spl/spl.c
			#else
				用户自定义
			#endif
		#else
			使用uboot的定义,位于common/board_r.c
		#endif

	SPL定义的board_init_r的调用过程:
		board_init_r
			spl_init
			timer_init
			board_boot_order
				spl_boot_device(获取启动介质,比如NandFlash,SDCARD)			位置由用户决定
				spl_load_image													common/spl/spl.c
					spl_<存储介质>_load_image									common/spl/spl_<存储介质>.c

			如果启动linux:
			spl_board_prepare_for_linux											common/spl/spl.c(本身是弱定义,用户可以自定义)
			jump_to_image_linux(启动linux)									arch/arm/lib/spl.c

			如果启动uboot:
			jump_to_image_no_args(启动uboot)									common/spl/spl.c(本身是弱定义,用户可以自定义)
注5:init_sequence_f是一个函数指针数组,包含大量初始化函数
注6:init_sequence_f常用函数(uboot不规定这些函数放在哪):
		board_early_init_f(做什么由用户自定义)
		timer_init(不带中断的定时器初始化)
		show_board_info(打印板子信息)
		misc_init_f(杂项初始化)
		dram_init(向gd->ram_size中写入SDRAM的大小)
		testdram(测试RAM)
注7:这个函数是弱定义,用户驱动可以重定义
注8:init_sequence_r常用函数(uboot不规定这些函数放在哪):
		board_init(板子初始化)
		initr_serial(串口初始化)
		board_early_init_r(板子早期初始化。说是早期,它却在board_init之后)
		arch_early_init_r(架构早期初始化)
		initr_nand,initr_onenand,initr_mmc,initr_dataflash(名字写得很清楚了)
		mac_read_from_eeprom(从EEPROM中读取MAC地址)
		show_board_info(打印板子信息)
		arch_misc_init(架构相关的杂项初始化)
		misc_init_r(杂项初始化)
		interrupt_init(中断初始化)
		initr_enable_interrupts(使能中断)
		initr_status_led(状态灯初始化)
		initr_ethaddr(网络初始化)
		board_late_init(板子后期初始化)
		initr_net(网卡初始化)
		run_main_loop(uboot主循环)

2 部分重要函数

run_main_loop																	common/board_r.c
	main_loop(各种uboot组件初始化)											common/main.c
		setenv("ver", version_string)(把版本信息写进ver环境变量)
		run_preboot_environment_command(读取preboot环境变量并自动执行里面的动作)	common/main.c
		update_tftp(读取updatefile环境变量自动更新文件)						common/update.c
		bootdelay_process(读取bootdelay,bootretry,bootcmd等环境变量)		common/autoboot.c
			menu_show((注9))
		cli_secure_boot_cmd(如果设备树里有关于启动的环境变量则读取出来)		common/cli.c
		autoboot_command(执行启动倒计时,如果检测到空格键输出则执行bootcmd命令)	common/autoboot.c
		cli_loop															common/cli.c
			parse_file_outer											common/cli_hush.c
			cli_simple_loop(循环处理uboot命令行)								common/cli_simple.c
注9:menu_show这个函数允许用户自己创建自己的菜单,帮助文档:doc/README.menu
do_bootm																	common/cmd_bootm.c
	do_bootm_states															common/bootm.c
		...
		bootm_find_os(根据镜像头部信息识别操作系统)						common/bootm.c
		...
		bootm_os_get_boot_func(根据不同的操作系统返回各自的启动函数)		common/bootm_os.c
		...
		boot_selected_os													common/bootm_os.c
			arch_preboot_os(用户驱动在启动内核之前可以做一些自定义动作)	bootm_os.c
				do_bootm_linux												arch/arm/lib/bootm.c
					boot_prep_linux(读取bootargs环境变量并通过
					setup_XXX_tag准备好ATAGS,如果使用设备树则
					准备好设备树)											arch/arm/lib/bootm.c
					boot_jump_linux											arch/arm/lib/bootm.c
						一堆代码(从machid环境变量读取机器码,并传给R1寄存器)
						announce_and_cleanup								common/cmd_bootm.c
							cleanup_before_linux(关中断,关闭并清除cache)	arch/arm/cpu/arm920t/cpu.c
						启动内核(kernel_entry(0, machid, r2)。
						r0恒为0,r1等于机器码,r2等于ATAG地址或者设备树地址)

3 一些概念

SPL

SPL就是SecondaryProgramLoader的意思,用来把真正的uboot搬移到内存执行。
大多数系统启动的时候都是把uboot从存储器搬移到内存执行的。这个过程是由系统内部的BootROM完成的。
然而,出于内存大小的限制或者BootROM本身的限制,这个搬移的量各不相同。有些可以把整个uboot搬移,有些则不能。
对于那些不能把整个uboot搬移的系统,uboot提出了SPL这个方案。
SPL属于uboot的一部分,按说应该是FirstProgramLoader才对,但是uboot把BootROM也算进去了,所以是SecondaryProgramLoader。

SPL只能做一些简单而必要的事情,大概就是初始化SDRAM,存储器,搬移uboot。它的使能由*defconfig中的CONFIG_SPL=y控制。

SPL和uboot同时编译,链接的时候分开链接。由于共享一样的配置文件,所以配置文件中使用#ifdef CONFIG_SPL_BUILD这样的预编译来区分SPL和uboot,但是注意CONFIG_SPL_BUILD这个宏是uboot编译系统自动生成的,不能手动修改。

SPL和uboot也可以合成为一份固件,定义这个宏#define CONFIG_SPL_TARGET "u-boot-with-spl.bin"即可。

SPL的固件大小需要被限制,不然可能不能运行。用这个宏:CONFIG_SPL_STACK

4 杂项

  • 某些低版本uboot(大约是2020以下)要有ethact这个环境变量才能用网卡;
  • uboot把bootcmd这个环境变量删除它就不会跳内核;
  • uboot在SDRAM中的地址是CONFIG_SYS_TEXT_BASE,小心操作SDRAM的时候不要把这部分内存给改了;
  • 内核CONFIG_DEBUG_USER=y,uboot的bootargs中添加 user_debug=31可以看到更多打印;
  • run命令很有用,你可以自定义一个变量setenv burnkernel <nand erase ... && tftpboot ... && nand write ...>然后执行run burnkernel来简化烧录内核的过程;
  • uboot恢复env为默认设置:env default -a
  • uboot的配置文件有两份,一个是configs/*defconfig,一个是include/configs/<board_name>.h
  • uboot大概从2014年以后才支持menuconfig,在此之前uboot的配置跟linux很不一样;
  • uboot可以直接修改dtb;
  • 自动生成的配置文件:include/generated/autoconf.h;
  • 特殊环境变量:
    • ver 版本信息
    • preboot 一连串动作,uboot在进入命令后立即使用run执行的命令
    • updatefile uboot启动时自动使用TFTP更新的文件
    • loadaddr uboot的TFTP默认下载地址
    • bootargs 内核的启动命令行
    • bootcmd 这个变量只是指定一连串的用来启动内核的动作,相当于一个脚本
    • bootdelay 启动倒计时,可以被空格键打断
    • machid uboot启动内核时传的机器码
    • 可以在代码里搜索"getenv"来查看uboot都会读取哪些环境变量
  • gd中的常用成员
    • flags 启动阶段
    • have_console console串口是否初始化完成
    • bi_arch_number 传给内核的机器号
  • SOC驱动位置:arch/arm/mach-XXX,arch/arm/cpu/,board/
  • uboot支持简写:bootm可以写成boot
  • 怎样开启debug打印:#define DEBUG
  • 默认环境变量怎么设置
#define CONFIG_EXTRA_ENV_SETTINGS	\		/* 或者CONFIG_EXTRA_ENV_BOARD_SETTINGS */
	"bootargs=console=ttyO2,115200n8\0"	\
	"root=/dev/mmcblk0p2 rw rootwait\0"	\
	"uservar=hello\0"		/* 用户自定义环境变量 */
  • 常用命令:
bootm <uImage_addr> // 无设备树,bootm 0x30007FC0
bootm <uImage_addr> <initrd_addr> <dtb_addr> // 有设备树。initrd_addr没有则为-
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值