zoukankan      html  css  js  c++  java
  • 如何实现uboot和linux之间的参数传递

    参考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_linuxboot/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_kernellinux/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.cprom_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;

               }


     [xxx1]实际对应linux_argv的值,也就是指向存放参数的地址

     [xxx2]prom_init中,就有使用fw_arg0,fw_arg1,fw_arg2,fw_arg3的处理了,利用这些参数,恢复成全局变量:arcs_cmdline的值

     [xxx3]利用arcs_cmdline,得到command_lineboot_command_line的值

     [xxx5]uboot中,将linux内核释放到的内存地址

     [xxx6]存储bootpara参数的地址

     [xxx7]获取存储的bootpara参数内容

  • 相关阅读:
    事务 ~ 锁
    JDBC
    C# ~ 由 IDisposable 到 GC
    C# ~ 泛型委托
    函数式编程
    反射
    测试初识
    C# ~ 从 委托事件 到 观察者模式
    C# ~ 从 IEnumerable / IEnumerator 到 IEnumerable<T> / IEnumerator<T> 到 yield
    Java初识
  • 原文地址:https://www.cnblogs.com/lagujw/p/4003016.html
Copyright © 2011-2022 走看看