学习是为了提高技巧,而读书是为了提高素质

U-Boot中MAC地址设置及往内核中传递

技术文档 23437浏览 0评论

一、内核参数的传递
U-Boot向Linux驱动传递参数的方式有两种,一为在系统启动的时候由bootloader传入,还有一种是将驱动编译成模块,将参数作为模块加载的参数传入。

内核通过setup接口接受Bootloader传入的参数。方式如下:
static int __init param_mac_setup(char *str)
{

……

}

__setup("mac=", param_mac_setup);

这样,当在Bootloader中指定“mac=00:2E:79:38:6D:4E”,系统在加载这个模块的时候,就会执行相应的param_mac_setup()函数,而传入给它的参数就是等号后面的物理地址“00:2E:79:38:6D:4E”。这样,该函数就可以对它进行相应的处理。
在U-Boot中,默认设置mac地址的参数为ethaddr,我们可以用过setenv ethaddr Mac地址来设置开发板的mac地址。

二、bootm传递参数的方式
在bootm执行的流程图中,可以看到会调用do_bootm_linux()在执行Linux内核,内核的起始地址如下:

void (*theKernel)(int zero, int arch, uint params);
image_header_t *hdr = &header;
       theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

header是uImage的头部,通过头部,得到内核映像起始的执行地址,标识为theKernel。从中也可以看到,内核接受三个参数,第一个为0,第二个为系统的ID号,第三个是传入内核的参数。
在do_bootm_linux()的最后,会跳到内核去执行:
       theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
最后两个参数在board/smdk2410/smdk2410.c的board_init()中被初始化:
       /* arch number of SMDK2410-Board */
       gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; /* 193 */
       /* adress of boot parameters */
       gd->bd->bi_boot_params = 0x30000100;
可以看到,U-Boot传给内核的参数表存放在内存中起始偏移0x100的位置,这里只是指定了“指针”的位置,但还没初始化其中的值,这是在do_bootm_linux()中跳到内核前去完成的。
值得注意的是, 内核的默认运行地址的0x30008000,前面就是留给参数用的。所以一般不要将内核下载到该地址之前,以免冲掉了传给内核的参数。

三、参数列表的构建
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
    defined (CONFIG_CMDLINE_TAG) || \
    defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG)
       setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAG
       setup_serial_tag (&params);
#endif
#ifdef CONFIG_REVISION_TAG
       setup_revision_tag (&params);
#endif

#ifdef CONFIG_SETUP_MEMORY_TAGS
       setup_memory_tags (bd);
#endif

#ifdef CONFIG_CMDLINE_TAG
       setup_commandline_tag (bd, commandline);
#endif

#ifdef CONFIG_INITRD_TAG
       if (initrd_start && initrd_end)
              setup_initrd_tag (bd, initrd_start, initrd_end);
#endif

#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
       setup_videolfb_tag ((gd_t *) gd);
#endif
       setup_end_tag (bd);
#endif

四、解决U-Boot命令行中不能重新设置ethaddr的问题,经常会提示Can't overwrite "ethaddr"
common/cmd_nvedit.c中函数_do_setenv中找到

#ifndef CONFIG_ENV_OVERWRITE
/*
* Ethernet Address and serial# can be set only once,
* ver is readonly.
*/
#ifdef CONFIG_HAS_UID
/* Allow serial# forced overwrite with 0xdeaf4add flag */
if ( ((strcmp (name, "serial#") == 0) && (flag != 0xdeaf4add)) ||
#else
if ( (strcmp (name, "serial#") == 0) ||
#endif
((strcmp (name, "ethaddr") == 0)

#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)&& (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0)
#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
) ) {
printf ("Can't overwrite \"%s\"\n", name);
return 1;
}
#endif

把((strcmp (name, "ethaddr") == 0)替换成 (0 即可;
五.为了让U-Boot命令行中设置的参数ethaddr传递到内核,必须修改U-Boot和linux内核两个地方:
(1)U-Boot修改 : lib_arm/armlinux.c
    在     #ifdef CONFIG_CMDLINE_TAG
              setup_commandline_tag (bd, commandline);
    下面添加如下语句:
    char *buf1 = malloc(1024);
    sprintf(buf1, "%s mac=%s", getenv ("bootargs"), getenv ("ethaddr"));
    setup_commandline_tag (bd, buf1);
(2)linux内核修改:drivers/net/davinci_emac.c
static int emac_eth_setup(void)
    {
前面添加:
static char davinci_mac_addr_uboot[20] = "";
   static int __init param_mac_setup(char *str)
    {
        strncpy(davinci_mac_addr_uboot, str, sizeof(davinci_mac_addr_uboot));
   }
    __setup("mac=", param_mac_setup);
并在函数emac_eth_setup内部语句printk("TI DaVinci EMAC: MAC address is %s\n", emac_eth_string);前面添加:
strncpy(emac_eth_string, davinci_mac_addr_uboot, sizeof(emac_eth_string));
添加完毕,重新编译uboot和内核。

参考文献:

http://hi.baidu.com/rwen2012/blog/item/8dba05a77523b690d14358d0.html

http://www.cublog.cn/u/15674/showart_1891479.html

转载请注明:自由的风 » U-Boot中MAC地址设置及往内核中传递

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址