1. 程式人生 > >U-Boot中MAC地址設定及往核心中傳遞

U-Boot中MAC地址設定及往核心中傳遞

一、核心引數的傳遞
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和核心。

參考文獻: