系统移植之uboot源代码简要分析(2)
来源:互联网 发布:网络借贷监管细则全文 编辑:程序博客网 时间:2024/06/03 19:12
经过上一篇系统移植之uboot源代码简要分析(1)对uboo进行分析后,我们知道BootLoader的第二阶段启动(BL2)从start_armboot处开始执行,start_armboot函数定义在“lib_arm/board.c”中
void start_armboot (void){ init_fnc_t **init_fnc_ptr; char *s; int mmc_exist = 0; ... for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { if ((*init_fnc_ptr)() != 0) /*返回值必须为0,否则初始化失败,系统初始化终止*/ { hang (); } }
init_fnc_t **init_fnc_ptr是一个二级指针,指向的内容为以下的数组init_sequence,该数组存储的是各类初始化函数的地址,start_armboot通过
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
循环逐个调用init_sequence数组中的初始化函数,完成对系统的初始化。
init_fnc_t *init_sequence[] = { cpu_init, /* basic cpu dependent setup */#if defined(CONFIG_SKIP_RELOCATE_UBOOT) reloc_init, /* Set the relocation done flag, must do this AFTER cpu_init(), but as soon as possible */#endif board_init, /* basic board dependent setup */ interrupt_init, /* set up exceptions */ env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_init, /* serial communications setup */ console_init_f, /* stage 1 init of console */ display_banner, /* say that we are here */#if defined(CONFIG_DISPLAY_CPUINFO) print_cpuinfo, /* display cpu info (and speed) */#endif#if defined(CONFIG_DISPLAY_BOARDINFO) checkboard, /* display board info */#endif#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) init_func_i2c,#endif dram_init, /* configure available RAM banks */ display_dram_config, NULL,};
另外,我们在start_armboot函数中可以见到很多个“gd_t”类型,该类型是定义于“include/asm-arm/globle_data.h”,是uboot的全局变量类型,
typedef struct global_data { bd_t *bd; unsigned long flags; unsigned long baudrate; ... void **jt; /* jump table */} gd_t;
在include/asm-arm/globle_data.h的最后,我们发现一段比较难懂的C语句
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
这句话的意思是指定R8保存变量gd的地址,并声明该值是volatile(易变的),然后用“DECLARE_GLOBAL_DATA_PTR”表示它。
在gd_t类型结构体中,我们需要重点关注“bd_t”这个类型结构体(开发板信息结构体),它与我们的移植的关联很大。这个结构体定义在“include/asm-arm/uboot.h”中↓
typedef struct bd_info { int bi_baudrate; /* serial console baudrate (串口控制台波特率)*/ unsigned long bi_ip_addr; /* IP Address */ unsigned char bi_enetaddr[6]; /* Ethernet adress */ struct environment_s *bi_env; ulong bi_arch_number; /* unique id for this board (机器码,即开发板ID,当且仅当ID在内核中存在且正确时候,才可进行启动)*/ ulong bi_boot_params; /* where this board expects params uboot传递给内核的参数的地址*/ struct /* RAM configuration DRAM的起始地址和大小*/ { ulong start; ulong size; }bi_dram[CONFIG_NR_DRAM_BANKS]; /*CONFIG_NR_DRAM_BANKS是允许的DRAM的数量*/#ifdef CONFIG_HAS_ETH1 /* second onboard ethernet port */ unsigned char bi_enet1addr[6];#endif} bd_t;/*开发板信息结构体*/
回到start_armboot函数
经过for循环调用各个初始化函数完成基础硬件的初始化,以及SOC的其他初始化(此处不累赘,对我们理解uboot启动流程没有太大影响)之后,程序进入”main_loop()”
main_loop函数定义于:common/main.c
/* main_loop() can return to retry autoboot, if so just run it again. */ for (;;) { main_loop (); }
main_loop的执行流程:
我们知道BootLoader有两种启动流程
1. 启动加载(boot loading)模式:
常用于已发布的产品上,整个过程不需要用户介入。
2. 下载(downloading)模式:
开发人员可以使用各种命令,通过串口连接或者网络连接等通信手段从主机(host)下载文件。常用协议:x/y/z modem协议、TFTP、nfs协议、USB。
进入main_loop后,执行流程如上图main_loop的执行流程所示。
函数首先读取环境参数bootdelay和bootcmd,然后判断bootdelay秒内串口是否有输入,
1>有输入,进入downloading模式
2>无输入,进入boot loading模式,启动加载内核;
~(启动内核–>是通过环变量bootcmd中存放的内核相关启动命令来启动内核的,这些命令有以下一些:
print(printenv):打印环境变量;
set(setenv):设置环境变量
saveenv:保存环境变量;
tftp:通过TFTP服务下载TFTP服务器目录下的文件到内存中
go:执行内存中的二进制代码
bootm:启动内存中的内核镜像文件zImage
…
)
那么这些内核启动命令是如何定义的呢?↓
内核启动命令定义于“include/command.h”中,类型定义方式如下
/* uboot命令结构体 */struct cmd_tbl_s { char *name; /* Command Name 命令名 */ int maxargs; /* maximum number of arguments命令最大参数个数 */ int repeatable; /* autorepeat allowed? 重复次数 */ /* Implementation function 命令处理函数 */ int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); char *usage; /* Usage message (short)简单使用信息 */#ifdef CFG_LONGHELP char *help; /* Help message (long)详细帮助信息 */#endif#ifdef CONFIG_AUTO_COMPLETE /* do auto completion on the arguments */ int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);#endif};/*将uboot命令结构体声明为cmd_tbl_t*/typedef struct cmd_tbl_s cmd_tbl_t;
好,接下来我们分析启动命令具体是如何定义的
/* * Command Flags: */#define CMD_FLAG_REPEAT 0x0001 /*repeat last command */#define CMD_FLAG_BOOTD 0x0002 /* command is from bootd *//* *1.这段宏定义具体意思:如果Struct_Section没被使用(unused),则 *将Struct_Section连接到启动命令段(".u_boot_cmd")中 **.u_boot_cmd定义于链接脚本uboot.lds中* */#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))#ifdef CFG_LONGHELP /*如果定义了详细帮助信息*//* *2.定义一个带参宏U_BOOT_CMD,表示后面的定义 *2.1)"##"连接符号,表示将__u_boot_cmd和name连接成为__u_boot_cmd_name *2.2)Struct_Section 将“__u_boot_cmd_name”到“.u_boot_cmd”启动代码段 */#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}/**/#else /* no long help info 没有详细帮助信息 */#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}#endif /* CFG_LONGHELP */
到”common/command.c”中可以查看具体定义了哪些命令。
我们再来看看“bootm”命令具体是如何启动内存中的内核镜像文件zImage的。
bootm命令定义在“common/cmd_bootm.c”
因为uboot是通用型BootLoader,可知uboot可以支持多种操作系统的启动,因此bootm命令需要根据具体操作系统分支执行,
switch (os) { default: /* handled by (original) Linux case */ case IH_OS_LINUX:#ifdef CONFIG_SILENT_CONSOLE fixup_silent_linux();#endif do_bootm_linux (cmdtp, flag, argc, argv, &images); break;...#ifdef CONFIG_ARTOS case IH_OS_ARTOS: do_bootm_artos (cmdtp, flag, argc, argv, &images); break;#endif }
我们使用是操作系统为Linux,选择分支为“IH_OS_LINUX”,接下来调用“do_bootm_linux (cmdtp, flag, argc, argv, &images);”进行启动。
do_bootm_linux函数定义于lib_arm/bootm.c 中
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], bootm_headers_t *images){ ulong initrd_start, initrd_end; ulong ep = 0; bd_t *bd = gd->bd; char *s; int machid = bd->bi_arch_number; /*获取机器ID*/ void (*theKernel)(int zero, int arch, uint params); int ret; ... cleanup_before_linux (); /* *将参数:0,机器ID,uboot传递给内核的参数的地址 *传递thekernel函数,进而启动内核。 */ theKernel (0, machid, bd->bi_boot_params); /* *至此,uboot的全部工作完成,接下来由内核接管系统。 */ /* does not return */ return;error: do_reset (cmdtp, flag, argc, argv); return;}
系统移植之uboot源代码简要分析如上,与各位道嵌友交流,若有谬误还望指教,谢谢!
- 系统移植之uboot源代码简要分析(2)
- 系统移植之uboot源代码简要分析(1)
- uboot源代码分析及移植
- uboot源代码分析及移植
- uboot源代码分析及移植
- 【系统移植】uboot详细分析
- 【转】uboot源代码分析及移植
- 嵌入式linux之Uboot和系统移植--主Makefile分析
- uboot移植之Makefile分析
- uboot移植之配置分析
- uboot移植 之 2
- uboot 移植之默认配置文档简要介绍
- Android日志系统Logcat源代码简要分析
- Android日志系统Logcat源代码简要分析
- Android日志系统Logcat源代码简要分析
- Android日志系统Logcat源代码简要分析
- Android日志系统Logcat源代码简要分析
- Android日志系统Logcat源代码简要分析
- 七牛——对象存储
- 几个python简单爬虫实例
- OpenXES开源库介绍
- JAVA之装饰者模式
- 《深入理解Java虚拟机》个人读书总结——虚拟机类加载机制
- 系统移植之uboot源代码简要分析(2)
- Map集合的EntrySet方法
- Qt 子窗口上控件的槽函数不响应
- HDU 4870 Rating 概率DP(高斯消元)
- idea 部署spring springMVC 与mybatis的整合
- Stream API
- hdu 2222 keywords search (AC自动机 模板)
- 关于学习NDK基础知识这些就够了(一)
- 西部开源运维unit7