参考http://cgxcn.blog.163.com/blog/static/132312422009101133251202/
参考:http://blog.chinaunix.net/uid-14833587-id-76499.html
参考:http://lixuefeng26.blog.sohu.com/204383842.html
原理就是:uboot将要传递的参数,保存到一个指定的物理位置;然后linux从该物理位置获取数据即可
1.先看一下uboot自带的参数传递过程:
A. 首先说明两个结构体:
boot/u-boot/include/asm-mips
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
unsigned long ram_size; /* RAM size */
unsigned long reloc_off; /* Relocation Offset */
unsigned long env_addr; /* Address of Environment struct */
unsigned long env_valid; /* Checksum of Environment valid? */
void **jt; /* jump table */
} gd_t
和
boot/u-boot/include/asm-mips
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
unsigned char bi_enetaddr[6]; /* Ethernet adress */
unsigned long bi_arch_number; /* unique id for this board */
unsigned long bi_boot_params; /* where this board expects params */
unsigned long bi_memstart; /* start of DRAM memory */
unsigned long bi_memsize; /* size of DRAM memory in bytes */
unsigned long bi_flashstart; /* start of FLASH memory */
unsigned long bi_flashsize; /* size of FLASH memory */
unsigned long bi_flashoffset; /* reserved area for startup monitor */
} bd_t;
B. 在do_bootm_linux(boot/u-boot/lib_mips/mips_linux.c)中,有如下处理:
linux_params_init (UNCACHED_SDRAM (gd->bd->bi_boot_params), commandline); --- 此函数,就是将commandline所指示的启动参数,存放到UNCACHED_SDRAM (gd->bd->bi_boot_params)所指示的物理地址中;同时,利用全局变量linux_argc,linux_argv,linux_env来分别指示这些参数的总数,位置以及环境变量的位置
#if defined(CONFIG_AR7100) || defined(CONFIG_AR7240)
/* Pass the flash size as expected by current Linux kernel for AR7100 */
flash_size_mbytes = gd->bd->bi_flashsize/(1024 * 1024);
theKernel (linux_argc, linux_argv, linux_env, flash_size_mbytes); /*启动内核,也就是说从ntohl (hdr->ih_ep)这个地址开始运行(这里不是函数调用,而是直接运行此地址上的东西;具体就是kernel_entry),其传递的参数就是linux_argc, linux_argv, linux_env, flash_size_mbytes*/
#else
而在linux/kernels/mips-linux-2.6.31/arch/mips/kernel/head.S中,有:
NESTED(kernel_entry, 16, sp)
LONG_S a0, fw_arg0 # firmware arguments
LONG_S a1, fw_arg1[xxx1]
LONG_S a2, fw_arg2
LONG_S a3, fw_arg3
……..
j start_kernel
这些,就是将四个参数:linux_argc, linux_argv, linux_env, flash_size_mbytes,分别传递给:fw_arg0,fw_arg1,fw_arg2,fw_arg3了;并且最终跳转到start_kernel函数中
C. 在start_kernel(linux/kernels/init/main.c)中,有:
->setup_arch(&command_line)(linux/kernels/arch/mips/kernel/setup.c)中,分别调用:
prom_init()(linux/kernels/arch/mips/xxx/prom.c)[xxx2] ;
arch_mem_init(cmdline_p); (linux/kernels/arch/mips/kernel/setup.c)[xxx3]
2. 那么,如果我们要将uboot下自定义的一些参数,传递给linux内核。该如何做? 这里,笔者由于工作需要,需要将uboot下记录的一个bootpara结构体参数,传递给linux内核。 实现方案如下:
² Cmd_bootm.c中的do_bootm函数,在:
case IH_COMP_LZMA:
printf (" Uncompressing %s ... ", name);
i = lzma_inflate ((unsigned char *)data, len, (unsigned char*)ntohl(hdr->ih_load), &unc_len);
if (i != LZMA_RESULT_OK) {
printf ("LZMA ERROR %d - must RESET board to recover ", i);
SHOW_BOOT_PROGRESS (-6);
udelay(100000);
do_reset (cmdtp, flag, argc, argv);
}
/*当解压缩内核成功后,则意味着后面就要调用do_bootm_linux启动内核了;那么这个时候,需要将uboot下记录的boot_para信息,存放到内存的指定位置;
从而传递给linux内核;
所选择的存放位置,需要放在内核解压缩地址的前面(这里留1K空间,存放bootpara参数);这样才能不会影响内核的启动*/
#ifdef CONFIG_XXX_BOOT
else {
unsigned int save_position = ntohl(hdr->ih_load) - 1024;[xxx4]
save_bootpara(save_position, &gBootPara);
}
#endif
break;
其中,
void save_bootpara(unsigned int save_position, T_BOOT_PARA *ptBootPara) {
memmove((unsigned char *)save_position, ptBootPara, sizeof(T_BOOT_PARA));
return;
}
² Prom.c的prom_init函数中,新增:
#define KERNEL_LOAD_ADDR 0x80002000[xxx5]
#ifdef CONFIG_XXX_BOOT
get_bootpara(KERNEL_LOAD_ADDR-1024[xxx6] , ptBootPara);
#endif
其中,
int get_bootpara(unsigned int load_position, T_BOOT_PARA *ptBootPara) {
memmove(ptBootPara, (unsigned char *)load_position, sizeof(T_BOOT_PARA));[xxx7]
return 0;
}