今天学了U_boot和Linux内核之间的参数传递,分享一下,写得不好勿怪......
u_boot完成的硬件的相关初始化,是知道Linux内核的相关信息的,但是Linux是直接被加载到内存中去的,刚开始对u_boot是一脸懵逼的,那怎么办呢?当然是u_boot告诉Linux内核一些信息,这就是所谓的参数传递。
u_boot主要传递给Linux内核3个参数:
r0:0x0
r1 : 开发板的ID ------------------ r1的参数,是让Linux内核自己去判断,它是否支持当前的开发板
r2 : 其他参数在内存中开始的地址
r2传递的开始地址中含有的信息
(1)内存的信息 -------- 内存的开始地址和内存的大小
(2)命令行参数:bootargs的内容--------------- 告诉Linux内核启动后,挂载文件系统的方式(例如:NFS方式)
(3)其他信息
r2只传递了开始的地址,并没有告诉Linux内核传递的参数内存的大小,那Linux内核是怎么知道什么时候结束的呢?
u_boot和Linux内核早就谈好了的,我们规定格式,双方按照规矩来办事。
目前Linux内核支持哪些格式的传递呢?
(1):通过struct parm_struct结构体来传递 (Linux 2.6之前使用的方式,已经过时,不便于扩展)
(2):通过tag列表来传递 (Linux 2.6开始使用的方式) -------- 一个tag节点包含了tag头 + 大小 + 内容
(3):通过设备树来传递(Linux 3.0开始使用的方式) ----- u_boot 修改了设备树的节点,把需要传递的信息放在了设备树中
我的环境是:Linux内核版本----3.2.0-29-generic-pae
ubuntu版本是12.04-1
下面是部分源码,大家想看源码的可以去u_boot下的arch/arm/lib/bootm.c查看(这是我的u_boot的路径,不同的内核或者BootLoader都可能不同)
/* Main Entry point for arm bootm implementation
*
* Modeled after the powerpc implementation
* DIFFERENCE: Instead of calling prep and go at the end
* they are called if subcommand is equal 0.
*/
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
/* No need for those on ARM */
if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
return -1;
if (flag & BOOTM_STATE_OS_PREP) {
boot_prep_linux(images);
return 0;
}
if (flag & BOOTM_STATE_OS_GO) {
boot_jump_linux(images);
return 0;
}
boot_prep_linux(images);
boot_jump_linux(images);
return 0;
}
/* Subcommand: PREP */
static void boot_prep_linux(bootm_headers_t *images)
{
#ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv("bootargs");
#endif
#ifdef CONFIG_OF_LIBFDT
if (images->ft_len) {
debug("using: FDT\n");
if (create_fdt(images)) {
printf("FDT creation failed! hanging...");
hang();
}
} else
#endif
/* Subcommand: GO */
static void boot_jump_linux(bootm_headers_t *images)
{
unsigned long machid = gd->bd->bi_arch_number;
char *s;
void (*kernel_entry)(int zero, int arch, uint params);
unsigned long r2;
kernel_entry = (void (*)(int, int, uint))images->ep;
s = getenv("machid");
if (s) {
strict_strtoul(s, 16, &machid);
printf("Using machid 0x%lx from environment\n", machid);
}
debug("## Transferring control to Linux (at address %08lx)" \
"...\n", (ulong) kernel_entry);
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
announce_and_cleanup();
#ifdef CONFIG_OF_LIBFDT
if (images->ft_len)
r2 = (unsigned long)images->ft_addr;
else
#endif
r2 = gd->bd->bi_boot_params;
kernel_entry(0, machid, r2);
}