U-Boot启动过程--详细版的完全分析

2026/4/29 11:51:28

… …

73 theKernel = (void (*)(int, int, uint))images->ep; /* 获取内核入口地址 */ … …

86 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \\ 87 defined (CONFIG_CMDLINE_TAG) || \\ 88 defined (CONFIG_INITRD_TAG) || \\ 89 defined (CONFIG_SERIAL_TAG) || \\ 90 defined (CONFIG_REVISION_TAG) || \\ 91 defined (CONFIG_LCD) || \\ 92 defined (CONFIG_VFD)

93 setup_start_tag (bd); /* 设置ATAG_CORE标志 */ … …

100 #ifdef CONFIG_SETUP_MEMORY_TAGS

101 setup_memory_tags (bd); /* 设置内存标记 */ 102 #endif

103 #ifdef CONFIG_CMDLINE_TAG

104 setup_commandline_tag (bd, commandline); /* 设置命令行标记 */ 105 #endif … …

113 setup_end_tag (bd); /* 设置ATAG_NONE标志 */ 114 #endif 115

116 /* we assume that the kernel is in place */ 117 printf (\ … …

126 cleanup_before_linux (); /* 启动内核前对CPU作最后的设置 */ 127

128 theKernel (0, machid, bd->bi_boot_params); /* 调用内核 */ 129 /* does not return */ 130

131 return 1; 132 }

其中的setup_start_tag,setup_memory_tags,setup_end_tag函数在lib_arm/bootm.c中定义如下:

(1)setup_start_tag函数

static void setup_start_tag (bd_t *bd) {

params = (struct tag *) bd->bi_boot_params; /* 内核的参数的开始地址 */

params->hdr.tag = ATAG_CORE; params->hdr.size = tag_size (tag_core);

params->u.core.flags = 0; params->u.core.pagesize = 0; params->u.core.rootdev = 0;

params = tag_next (params); }

标记列表必须以ATAG_CORE开始,setup_start_tag函数在内核的参数的开始地址设置了一个ATAG_CORE标记。 (2)setup_memory_tags函数 static void setup_memory_tags (bd_t *bd) { int i;

/*设置一个内存标记 */

for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { params->hdr.tag = ATAG_MEM;

params->hdr.size = tag_size (tag_mem32);

params->u.mem.start = bd->bi_dram[i].start; params->u.mem.size = bd->bi_dram[i].size;

params = tag_next (params); } }

setup_memory_tags函数设置了一个ATAG_MEM标记,该标记包含内存起始地址,内存大小这两个参数。 (3)setup_end_tag函数 static void setup_end_tag (bd_t *bd) {

params->hdr.tag = ATAG_NONE; params->hdr.size = 0; }

标记列表必须以标记ATAG_NONE结束,setup_end_tag函数设置了一个ATAG_NONE标记,表示标记列表的结束。

U-Boot设置好标记列表后就要调用内核了。但调用内核前,CPU必须满足下面的条件: (1) CPU寄存器的设置 ? r0=0 ? r1=机器码

? r2=内核参数标记列表在RAM中的起始地址 (2) CPU工作模式 ? 禁止IRQ与FIQ中断 ? CPU为SVC模式

(3) 使数据Cache与指令Cache失效

do_bootm_linux中调用的cleanup_before_linux函数完成了禁止中断和使Cache失效的功能。cleanup_before_linux函数在cpu/arm920t/cpu.中定义: int cleanup_before_linux (void) { /*

* this function is called just before we call linux * it prepares the processor for linux *

* we turn off caches etc ... */

disable_interrupts (); /* 禁止FIQ/IRQ中断 */

/* turn off I/D-cache */

icache_disable(); /* 使指令Cache失效 */ dcache_disable(); /* 使数据Cache失效 */ /* flush I/D-cache */

cache_flush(); /* 刷新Cache */

return 0; }

由于U-Boot启动以来就一直工作在SVC模式,因此CPU的工作模式就无需设置了。 do_bootm_linux中:

64 void (*theKernel)(int zero, int arch, uint params); … …

73 theKernel = (void (*)(int, int, uint))images->ep; … …

128 theKernel (0, machid, bd->bi_boot_params);

第73行代码将内核的入口地址“images->ep”强制类型转换为函数指针。根据ATPCS规则,函数的参数个数不超过4个时,使用r0~r3这4个寄存器来传递参数。因此第128行的函数调用则会将0放入r0,机器码machid放入r1,内核参数地址bd->bi_boot_params放入r2,从而完成了寄存器的设置,最后转到内核的入口地址。

到这里,U-Boot的工作就结束了,系统跳转到Linux内核代码执行。

1.1.4 U-Boot添加命令的方法及U-Boot命令执行过程

下面以添加menu命令(启动菜单)为例讲解U-Boot添加命令的方法。 (1) 建立common/cmd_menu.c

习惯上通用命令源代码放在common目录下,与开发板专有命令源代码则放在board/目录下,并且习惯以“cmd_<命令名>.c”为文件名。 (2) 定义“menu”命令

在cmd_menu.c中使用如下的代码定义“menu”命令: _BOOT_CMD(

menu, 3, 0, do_menu,

\ \);

其中U_BOOT_CMD命令格式如下:

U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) 各个参数的意义如下:

name:命令名,非字符串,但在U_BOOT_CMD中用“#”符号转化为字符串 maxargs:命令的最大参数个数

rep:是否自动重复(按Enter键是否会重复执行) cmd:该命令对应的响应函数 usage:简短的使用说明(字符串) help:较详细的使用说明(字符串)

在内存中保存命令的help字段会占用一定的内存,通过配置U-Boot可以选择是否保存help字段。若在include/configs/mini2440.h中定义了CONFIG_SYS_LONGHELP宏,


U-Boot启动过程--详细版的完全分析.doc 将本文的Word文档下载到电脑
搜索更多关于: U-Boot启动过程--详细版的完全分析 的文档
相关推荐
相关阅读
× 游客快捷下载通道(下载后可以自由复制和排版)

下载本文档需要支付 10

支付方式:

开通VIP包月会员 特价:29元/月

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:xuecool-com QQ:370150219