首先将BootLoader 传递过来的r1(机器编号)、r2(参数链表的物理地址)的值保存到r7、r8 中,再将r7 作为参数传递给解压函数decompress_kernel()。在解压函数中,再将r7 传递给全局变量__machine_arch_type。在跳到内核(vmlinux)入口之前再将r7,r8 还原到r1,r2 中。
在文件 arch/arm/kernel/head.S[2]中,内核(vmlinux)入口的部分代码如下:
stext:
mrc p15, 0, r9, c0, c0
bl __lookup_processor_type
………
bl __lookup_machine_type
首先从处理器内部特殊寄存器(CP15)中获得ARM 内核的类型,从处理器内核描述符(proc_info_list)表(__proc_info_begin—__proc_info_end)中查询有无此ARM 内核的类型,如果无就出错退出。处理器内核描述符定义在 include/asm-arm/procinfo.h中,具体的函数实现在 arch/arm/mm/proc-xxx.S中,在编译连接过程中将各种处理器内核描述符组合成表。接着从机器描述符(machine_desc)表(__mach_info_begin—__mach_info_end)中查询有无r1 寄存器指定的机器编号,如果没有就出错退出。机器编号mach_type_xxx 在arch/arm/tools/mach-types文件中说明,每个机器描述符中包括一个唯一的机器编号,机器描述符的定义在 include/asm-arm/mach/arch.h中,具体实现在 arch/arm/mach-xxxx文件夹中,在编译连接过程中将基于同一种处理器的不同机器描述符组合成表。例如,基于AT91RM9200 处理器的各种机器描述符可以参考 arch/arm/mach-at91rm9200/board-xxx.c,机器编号为262 的机器描述符如下所示:
MACHINE_START(AT91RM9200DK, “Atmel AT91RM9200-DK”)
/* Maintainer: SAN People/Atmel */
.phys_io = AT91_BASE_SYS,
.io_pg_offst = (AT91_VA_BASE_SYS 》》 18) & 0xfffc,
.boot_params = AT91_SDRAM_BASE + 0x100,
.timer = &at91rm9200_timer,
.map_io = dk_map_io,
.init_irq = dk_init_irq,
.init_machine = dk_board_init,
MACHINE_END
最后就是打开MMU,并跳转到 init/main.c的start_kernel(初始化系统。在 init/main.c中,函数start_kernel()的部分代码如下:
{
……
setup_arch();
……
}
在 arch/arm/kernel/setup.c中,函数setup_arch()的部分代码如下:
{
……
setup_processor();
mdesc=setup_machine(machine_arch_type);
……
parse_tags(tags);
……
}
setup_processor()函数从处理器内核描述符表中找到匹配的描述符,并初始化一些处理器变量。setup_machine()用机器编号(在解压函数decompress_kernel 中被赋值)作为参数返回机器描述符。从机器描述符中获得内核参数的物理地址,赋值给tags 变量。然后调用parse_tags()函数分析内核参数链表,把各个参数值传递给全局变量。这样内核就收到了BootLoader 传递的参数。
5. 参数传递的验证和测试
参数传递的结果可以通过内核启动的打印信息来验证。
Machine: Atmel AT91RM9200-DK
……
Kernel command line: console=ttyS0,115200 root=/dev/ram rw init=/linuxrc
……
Memory: 64MB = 64MB total
……
checking if image is initramfs.。.it isn‘’t (no cpio magic); looks like an initrd
Freeing initrd memory: 1024K
……
RAMDISK: Compressed image found at block 0
一个完备的BootLoader 是一个很复杂的工程,本文所介绍的只是嵌入式系统的BootLoaer 基本功能。任何一个BootLoader 都离不开这个基本功能,内核只有接收这些参数才能正确地启动,同时也为内核的移植和调试奠定了良好的基础。
bootm命令中通过拷贝tag传递参数
为方便阅读,进行了少许修改,但功能不变,该函数参数为存放启动参数的地址
static void setup_linux_tag(ulong param_base)
{
struct tag *params = (struct tag *)param_base;
char *linux_cmd;
char *p;
memset(params, 0, sizeof(struct tag));
/* step1: setup start tag */
params-》hdr.tag = ATAG_CORE;
params-》hdr.size = tag_size(tag_core);
params-》u.core.flags = 0;
params-》u.core.pagesize = LINUX_PAGE_SIZE;
params-》u.core.rootdev = 0;
params = tag_next(params);
/* step2: setup cmdline tag */
params-》hdr.tag = ATAG_CMDLINE;
linux_cmd = getenv(“bootargs”);
for (p=linux_cmd; *p==‘ ’; p++) {/* do nothing */;}
params-》hdr.size = (sizeof(struct tag_header)+strlen(linux_cmd)+1+4) 》》 2;
memcpy(params-》u.cmdline.cmdline, linux_cmd, strlen(linux_cmd)+1);
params = tag_next(params);
/* step3: setup end tag */
params-》hdr.tag = ATAG_NONE;
params-》hdr.size = 0;
}
在uboot中,进行设置tag的函数都在lib_arm/armlinux.c中,在这些函数前面是有ifdef的
#if defined (CONFIG_SETUP_MEMORY_TAGS) || /
defined (CONFIG_CMDLINE_TAG) || /
defined (CONFIG_INITRD_TAG) || /
defined (CONFIG_SERIAL_TAG) || /
defined (CONFIG_REVISION_TAG) || /
defined (CONFIG_LCD) || /
defined (CONFIG_VFD)
因此,如果你的bootm命令不能传递内核参数,就应该是在你的board的config文件里没有对上述的
宏进行设置,定义一下即可
评论