2022年Uboot如何向内核传递参数 .pdf
Uboot如何向内核传递参数一:启动参数的传递过程启动参数是包装在数据结构里的,在 linux kernel启动的时候,bootloader把这个数据结构拷贝到某个地址,在改动PC 跳向内核接口的同时,通过通用寄存器R2 来传递这个地址的值,下面这句话就是uboot跳向linux kernel的代码(bootm命令)theKernel(0,bd-bi_arch_number,bd-bi_boot_params);thekernel其实不是个函数,而是指向内核入口地址的指针,把它强行转化为带三个参数的函数指针,会把三个参数保存到通用寄存器中,实现了向 kernel传递信息的功能,在这个例子里,会把 R0 赋值为 0,R1赋值为机器号R2 赋值为启动参数数据结构的首地址因此,要向内核传递参数很简单,只要把启动参数封装在linux预定好的数据结构里,拷贝到某个地址(一般约定俗成是内存首地址+100dex)二:启动参数的数据结构启动参数可保存在两种数据结构中,param_struct和 tag,前者是 2.4 内核用的,后者是 2.6 以后的内核更期望用的但是,到目前为止,2.6 的内核也可以兼容前一种结构,两种数据结构具体定义如下(arm cpu):struct param_struct union struct unsigned long page_size;/*0*/unsigned long nr_pages;/*4*/unsigned long ramdisk_size;/*8*/unsigned long flags;/*12*/#define FLAG_READONLY 1#define FLAG_RDLOAD 4#define FLAG_RDPROMPT 8 unsigned long rootdev;/*16*/unsigned long video_num_cols;/*20*/unsigned long video_num_rows;/*24*/unsigned long video_x;/*28*/unsigned long video_y;/*32*/unsigned long memc_control_reg;/*36*/unsigned char sounddefault;/*40*/unsigned char adfsdrives;/*41*/unsigned char bytes_per_char_h;/*42*/unsigned char bytes_per_char_v;/*43*/unsigned long pages_in_bank4;/*44*/unsigned long pages_in_vram;/*60*/名师资料总结-精品资料欢迎下载-名师精心整理-第 1 页,共 4 页 -unsigned long initrd_start;/*64*/unsigned long initrd_size;/*68*/unsigned long rd_start;/*72*/unsigned long system_rev;/*76*/unsigned long system_serial_low;/*80*/unsigned long system_serial_high;/*84*/unsigned long mem_fclk_21285;/*88*/s;char unused256;u1;union char paths8128;struct unsigned long magic;char n1024-sizeof(unsigned long);s;u2;char commandlineCOMMAND_LINE_SIZE;param_struct只需要设置 cmmandline,u1.s.page_size,u1.s.nr_pages三个域,具体使用可参见下面的例子对于 tag 来说,在实际使用中是一个struct tag组成的列表,在 tag-tag_header中,一项是 u32 tag(重名,注意类型)其值用宏 ATAG_CORE,ATAG_MEM,ATAG_CMDLINE,ATAG_NONE等等来表示,此时下面 union就会使用与之相关的数据结构同时,规定 tag列表中第一项必须是ATAG_CORE,最后一项必须是ATAG_NONE,比如在linux代码中,找到启动参数之后首先看 tag 列表中的第一项的tag-hdr.tag是否为 ATAG_CORE,如果不是,就会认为启动参数不是tag结构而是 param_struct 结构,然后调用函数来转换.在 tag-tag_header中,另一项是 u32 size,表示 tag 的大小,tag 组成列表的方式就是指针+size,实际使用中用tag_next(params).tag的具体使用见三中的例子struct tag struct tag_header hdr;union struct tag_core core;struct tag_mem32 mem;struct tag_videotext videotext;struct tag_ramdisk ramdisk;struct tag_initrd initrd;struct tag_serialnr serialnr;struct tag_revision revision;struct tag_videolfb videolfb;struct tag_cmdline cmdline;名师资料总结-精品资料欢迎下载-名师精心整理-第 2 页,共 4 页 -struct tag_acorn acorn;/Acorn specific struct tag_omap omap;/OMAP specific struct tag_memclk memclk;/DC21285 specific u;需要注意的是,这两个数据结构在uboot中和 linux中分别有定义,这个定义必须一直才能正常传递参数如果实际使用中不一致的话就不能正常传递,可以自行修改三:通过两种数据结构传递参数的具体例子1:例子一:通过 param_struct让 uboot中的 go 命令可以传递参数分析:go的代码在common/cmd_boot.c中,里面并没有拷贝启动参数的代码,转向内核的时候也没有传送启动参数所在的地址,因此添加如下代码用于拷贝参数,可以看到,对于param_struct只需要设置cmmandline u1.s.page_size,u1.s.nr_pages三个域 char*commandline=getenv(bootargs);struct param_struct*lxy_params=(struct param_struct*)0 x80000100;printf(setup linux parameters at 0 x80000100n);memset(lxy_params,0,sizeof(struct param_struct);lxy_params-u1.s.page_size=(0 x1u1.s.nr_pages=(0 x4000000)12;/64M 这个是必须有的,否则无法启动memcpy(lxy_params-commandline,commandline,strlen(commandline)+1);printf(linux command line is:%sn,lxy_params-commandline);然后还要向内核传递参数地址,将下面一行代码修改:rc=(ulong(*)(int,char*)addr)(-argc,&argv1);/需要被修改的代码rc=(ulong(*)(int,int,uint)addr)(0,gd-bd-bi_arch_number,gd-bd-bi_boot_params);/修改之后的代码2:例子二: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;名师资料总结-精品资料欢迎下载-名师精心整理-第 3 页,共 4 页 -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);/*eat leading white space*/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文件里没有对上述的宏进行设置,定义一下即可名师资料总结-精品资料欢迎下载-名师精心整理-第 4 页,共 4 页 -