bootargs 是 uboot 在启动 Linux 内核时传递给内核的引导参数,参数中一般包含启动存储介质、文件系统分区及挂载方式和终端串口等参数。
在系统中我们可以通过 /proc/cmdline 来查看 uboot 给 kernel 传递的 bootargs 参数内容。
# cat /proc/cmdline storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal androidboot.slot_suffix= androidboot.serialno=c3d9b8674f4b94f6 rw rootwait earlycon=uart8250,mmio32,0xff160000 swiotlb=1 console=ttyFIQ0 root=PARTUUID=614e0000-0000
Rockchip PX30芯片只有一路以太网,为了满足一些多网口的应用场景,会使用 USB 转以太网口芯片来扩展以太网接口。以Realtek r8152芯片为例,转换芯片自身不带硬件MAC地址,这将导致每次系统启动,网卡的MAC也会随机变化而非固定;可以在驱动加载时将固定的自定义的MAC地址设置给网卡,以解决MAC地址不固定的问题。
Rockchip在eMMC的首部保留了一块用于存储序列号、MAC等自定义内容的Vendor Storage存储空间。
Vendor Storage在eMMC中的位置:
Vendor Storage 结构:
Vendors Storage 各ID内容序号:
使用Rockchip写号工具向Vendor Storage区域写入自定义的MAC地址,之后在程序中读取出Vendor Storage中保存的MAC地址来实现MAC地址的设置。PX30芯片自带网卡的MAC设置使用的是LAN MAC存储段的数据,给 USB转网口芯片的网卡设置固定MAC,可以选择Vendor Storage中未被使用的BT MAC ID段来保存MAC地址。
本章以Rockchip PX30 linux SDK为基础添加Vendors Storage BT MAC 字段的读取,并通过 bootargs 参数传递给kernel。
uboot源码的 arch/arm/mach-rockchip/ 为rockchip平台相关代码目录,在 arch/arm/mach-rockchip/board.c 文件中添加Vendor Storage BT MAC内容的读取,并将读取出MAC地址设置给变量 bt_mac。详细代码如下:
--- a/arch/arm/mach-rockchip/board.c +++ b/arch/arm/mach-rockchip/board.c @@ -74,6 +74,24 @@ __weak int rk_board_init(void) #define CPUID_LEN 0x10 #define CPUID_OFF 0x07 +static int rockchip_get_bt_mac(void) +{ +#ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION + char buf[ARP_HLEN_ASCII + 1]; + u8 ethaddr[ARP_HLEN]; + int ret; + + ret = vendor_storage_read(VENDOR_BLUETOOTH_ID, ethaddr, sizeof(ethaddr)); + if (ret > 0 && is_valid_ethaddr(ethaddr)) { + sprintf(buf, "%pM", ethaddr); + env_set("bt_mac", buf); + } +#endif + return 0; + +} + static int rockchip_set_ethaddr(void) { #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION @@ -161,6 +179,7 @@ int fb_set_reboot_flag(void) int board_late_init(void) { + rockchip_get_bt_mac(); rockchip_set_ethaddr(); rockchip_set_serialno(); #if (CONFIG_ROCKCHIP_BOOT_MODE_REG > 0)
在uboot的 arch/arm/lib/bootm.c 文件中找到 boot_prep_linux 函数,此函数包含读取 bootargs 参数并将其保存至指定的位置,在最后跳转执行内核时作为参数传递给内核入口函数。只需在bootargs传递之前,给bootargs添加一个bt_mac字段即可。详细代码如下:
--- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -224,8 +224,27 @@ static void do_nonsec_virt_switch(void) /* Subcommand: PREP */ static void boot_prep_linux(bootm_headers_t *images) { - char *commandline = env_get("bootargs"); +#ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION + char *commandline = NULL; + char new_bootargs[512] = {0}; + char* old_bootargs = env_get("bootargs"); + int old_len = strlen(old_bootargs); + char *bt_mac = env_get("bt_mac"); + + if(bt_mac){ + strncpy(new_bootargs, old_bootargs, old_len); + sprintf(new_bootargs, "%s %s%s", new_bootargs, "bt_mac=", env_get("bt_mac")); + env_set("bootargs", new_bootargs); + } + commandline = env_get("bootargs"); +#else + char *commandline = env_get("bootargs"); +#endif if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) { #ifdef CONFIG_OF_LIBFDT debug("using: FDT\n");
在Linux 内核 r8152 的驱动 drivers\net\usb\r8152.c 中,使用 __setup 函数来获取bootargs中的bt_mac字段并检查MAC的合法性;并在网卡MAC地址设置函数中,将合法的MAC设置给USB网卡。详细代码如下:
--- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -27,6 +27,15 @@ #include <linux/usb/cdc.h> #include <linux/suspend.h> +#define R8152_USE_BT_MAC_ADDR +#ifdef R8152_USE_BT_MAC_ADDR +#define BT_MAC_STR_LEN 17 //e.g. AA:BB:CC:DD:EE:FF +static unsigned char uboot_get_btmac_flag = 0; +static unsigned char mac_addr_str[18]= {0}; +static char bt_mac_addr_hex[6] = {0}; +#endif + /* Information for net-next */ #define NETNEXT_VERSION "08" @@ -1042,6 +1051,16 @@ static int set_ethernet_addr(struct r8152 *tp) else ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data); +#ifdef R8152_USE_BT_MAC_ADDR + if(uboot_get_btmac_flag && is_valid_ether_addr(bt_mac_addr_hex)){ + ether_addr_copy(sa.sa_data, bt_mac_addr_hex); + + ret = rtl8152_set_mac_address(dev, &sa); + netif_info(tp, probe, dev, "bt_mac ether addr %pM\n", sa.sa_data); + return ret; + } +#endif + if (ret < 0) { netif_err(tp, probe, dev, "Get ether addr fail\n"); } else if (!is_valid_ether_addr(sa.sa_data)) { @@ -4357,6 +4376,25 @@ static void rtl8152_disconnect(struct usb_interface *intf) free_netdev(tp->netdev); } } +#ifdef R8152_USE_BT_MAC_ADDR +static int __init get_bt_mac_addr(char* str) +{ + if(!strcmp(str,"<NULL>") || (BT_MAC_STR_LEN != strlen(str))){ + printk("bt_mac get failed\n"); + return 0; + } + + strncpy(mac_addr_str,str, BT_MAC_STR_LEN); + sscanf(mac_addr_str, "%02x:%02x:%02x:%02x:%02x:%02x", \ + (int*)&bt_mac_addr_hex[0], (int*)&bt_mac_addr_hex[1], \ + (int*)&bt_mac_addr_hex[2], (int*)&bt_mac_addr_hex[3], \ + (int*)&bt_mac_addr_hex[4], (int*)&bt_mac_addr_hex[5]); + + if(is_valid_ether_addr(bt_mac_addr_hex)){ + uboot_get_btmac_flag = 1; + } + return 0; +} +__setup("bt_mac=",get_bt_mac_addr); +#endif #define REALTEK_USB_DEVICE(vend, prod) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
使用RKDevInfoWriteTool软件向BT MAC地址写入0A0C11223345
系统启动后,查看/proc/cmdline 可看到 bt_mac=0a:0c:11:22:33:45 ,说明bootargs修改成功。
# cat /proc/cmdline storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal androidboot.slot_suffix= androidboot.serialno=A5303202110A0000001 bt_mac=0a:0c:11:22:33:45 rw rootwait earlycon=uart8250,mmio32,0xff160000 swiotlb=1 console=ttyFIQ0 root=PARTUUID=614e0000-0000
查看网卡MAC地址也已设置为烧录的MAC
# ifconfig eth1 eth1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 ether 0a:0c:11:22:33:45 txqueuelen 1000 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!