Uboot通过bootargs给Kernel传递自定义MAC

本文以 PX30 USB网卡设置自定义MAC为例,分享如何在bootargs参数基础上添加自定义字段,实现uboot向kernel传递参数。

一、关于bootargs

        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

二、网卡自定义MAC

        Rockchip PX30芯片只有一路以太网,为了满足一些多网口的应用场景,会使用 USB 转以太网口芯片来扩展以太网接口。以Realtek r8152芯片为例,转换芯片自身不带硬件MAC地址,这将导致每次系统启动,网卡的MAC也会随机变化而非固定;可以在驱动加载时将固定的自定义的MAC地址设置给网卡,以解决MAC地址不固定的问题。

        Rockchip在eMMC的首部保留了一块用于存储序列号、MAC等自定义内容的Vendor Storage存储空间。

Vendor Storage在eMMC中的位置:

attachments-2021-12-4kC31LNP61bc0401143fa.png

Vendor Storage 结构:

attachments-2021-12-9YrUeqpg61bc0423ebcce.png

Vendors Storage 各ID内容序号:

attachments-2021-12-zvdWK9C761bc0439b5cab.png

        使用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中读取Vendor Storage

        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)

在bootargs参数中添加MAC地址字段

        在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");

kernel中获取MAC地址并设置

        在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

attachments-2021-12-ezsq8Mjo61bc0479a3e6c.png

系统启动后,查看/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



  • 发表于 2021-12-17 11:32
  • 阅读 ( 1293 )

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
FU
FU

9 篇文章

作家榜 »

  1. BBelephant 13 文章
  2. ronnie 11 文章
  3. FU 9 文章
  4. toca 4 文章
  5. 大飞 3 文章
  6. Vivek 3 文章
  7. jack-fang 2 文章
  8. Bin 1 文章