uboot env ethaddr 是如何生成的

uboot env ethaddr 是如何生成的?

思考

默认环境变量中并不会指定 ethaddr , 然而板子起来后会自己生成ethaddr 变量,并且各个板子的ethaddr 是唯一的。并且即使清除env分区,重新启动后ethaddr 也不会变。是如何做到的?

  • ethaddr 变量是何时设置的?
  • 是如何做各个板子唯一的?
  • 为何清除env 分区,重新启动也不会变?
  • ethaddr 可以手动设置吗?

ethaddr 变量是何时设置的?

在uboot/doc/README.enetaddr 中有说明:

-------
 Usage
-------

If the hardware design mandates that the MAC address is stored in some special
place (like EEPROM etc...), then the board specific init code (such as the
board-specific misc_init_r() function) is responsible for locating the MAC
address(es) and initializing the respective environment variable(s) from it.
Note that this shall be done if, and only if, the environment does not already
contain these environment variables, i.e. existing variable definitions must
not be overwritten.

大意是必须在 misc_init_r 函数中对 ethaddr 进行设置。

以sun8i-h3 为例,跟踪一下代码:

misc_init_r   //u-boot-2017.11.git\board\sunxi\board.c
-> setup_environment(gd->fdt_blob);
static void setup_environment(const void *fdt)
{
    
    
	char serial_string[17] = {
    
     0 };
	unsigned int sid[4];
	uint8_t mac_addr[6];
	char ethaddr[16];
	int i, ret;

	ret = sunxi_get_sid(sid);     // sid 是 h3 芯片的唯一id,每块芯片不一样
	if (ret == 0 && sid[0] != 0) {
    
    
		/*
		 * The single words 1 - 3 of the SID have quite a few bits
		 * which are the same on many models, so we take a crc32
		 * of all 3 words, to get a more unique value.
		 *
		 * Note we only do this on newer SoCs as we cannot change
		 * the algorithm on older SoCs since those have been using
		 * fixed mac-addresses based on only using word 3 for a
		 * long time and changing a fixed mac-address with an
		 * u-boot update is not good.
		 */
#if !defined(CONFIG_MACH_SUN4I) && !defined(CONFIG_MACH_SUN5I) && \
    !defined(CONFIG_MACH_SUN6I) && !defined(CONFIG_MACH_SUN7I) && \
    !defined(CONFIG_MACH_SUN8I_A23) && !defined(CONFIG_MACH_SUN8I_A33)
		sid[3] = crc32(0, (unsigned char *)&sid[1], 12);
#endif

		/* Ensure the NIC specific bytes of the mac are not all 0 */
		if ((sid[3] & 0xffffff) == 0)
			sid[3] |= 0x800000;

		for (i = 0; i < 4; i++) {
    
    
			sprintf(ethaddr, "ethernet%d", i);
			if (!fdt_get_alias(fdt, ethaddr))
				continue;

			if (i == 0)
				strcpy(ethaddr, "ethaddr");
			else
				sprintf(ethaddr, "eth%daddr", i);

			if (env_get(ethaddr))
				continue;

			/* Non OUI / registered MAC address */
			mac_addr[0] = (i << 4) | 0x02;
			mac_addr[1] = (sid[0] >>  0) & 0xff;
			mac_addr[2] = (sid[3] >> 24) & 0xff;
			mac_addr[3] = (sid[3] >> 16) & 0xff;
			mac_addr[4] = (sid[3] >>  8) & 0xff;
			mac_addr[5] = (sid[3] >>  0) & 0xff;

			eth_env_set_enetaddr(ethaddr, mac_addr);
		}		
	}
}

sid 对应于手册上的 Seurity ID:

至此,可以解答前三个问题:

  • ethaddr 变量是何时设置的?

    答:misc_init_r -> setup_environment 中设置

  • 是如何做各个板子唯一的?

    答:因为是通过读取芯片sid , 来生成mac 地址。

  • 为何清除env 分区,重新启动也不会变?

    答:因为sid 存在芯片内部,只要芯片没换就不会变。

ethaddr 可以手动设置吗?

默认不能。

=> setenv ethaddr d0:00:00:00:00:01
## Error: Can't overwrite "ethaddr"
## Error inserting "ethaddr" variable, errno=1
=> 

可见 uboot 中对 ethaddr 做了写权限限制。

开启 CONFIG_CMD_ENV_FLAGS=y , 可通过 env flags 查看一些变量的权限。

=> env flags
Available variable type flags (position 0):
        Flag    Variable Type Name
        ----    ------------------
        s   -   string
        d   -   decimal
        x   -   hexadecimal
        b   -   boolean
        i   -   IP address
        m   -   MAC address

Available variable access flags (position 1):
        Flag    Variable Access Name
        ----    --------------------
        a   -   any
        r   -   read-only
        o   -   write-once
        c   -   change-default

Static flags:
        Variable Name        Variable Type        Variable Access     
        -------------        -------------        ---------------     
        eth\d?addr           MAC address          write-once          
        ipaddr               IP address           any                 
        gatewayip            IP address           any                 
        netmask              IP address           any                 
        serverip             IP address           any                 
        nvlan                decimal              any                 
        vlan                 decimal              any                 
        dnsip                IP address           any                 
        serial#              string               write-once          

Active flags:
        Variable Name        Variable Type        Variable Access     
        -------------        -------------        ---------------     
        serial#              string               write-once          
        ethaddr              MAC address          write-once          
        serverip             IP address           any                 
        ipaddr               IP address           any                 

在uboot/README 中有如下说明:

- Vendor Parameter Protection:

                U-Boot considers the values of the environment
                variables "serial#" (Board Serial Number) and
                "ethaddr" (Ethernet Address) to be parameters that
                are set once by the board vendor / manufacturer, and
                protects these variables from casual modification by
                the user. Once set, these variables are read-only,
                and write or delete attempts are rejected. You can
                change this behaviour:

                If CONFIG_ENV_OVERWRITE is #defined in your config
                file, the write protection for vendor parameters is
                completely disabled. Anybody can change or delete
                these parameters.

                Alternatively, if you define _both_ an ethaddr in the
                default env _and_ CONFIG_OVERWRITE_ETHADDR_ONCE, a default
                Ethernet address is installed in the environment,
                which can be changed exactly ONCE by the user. [The
                serial# is unaffected by this, i. e. it remains
                read-only.]

                The same can be accomplished in a more flexible way
                for any variable by configuring the type of access
                to allow for those variables in the ".flags" variable
                or define CONFIG_ENV_FLAGS_LIST_STATIC.

可见uboot 专门对 serial# ethaddr 等变量做了保护措施,默认不可修改,如需修改,需要打开 CONFIG_ENV_OVERWRITE=y 配置选项。

猜你喜欢

转载自blog.csdn.net/agave7/article/details/108737595
env