RK3576 android14 GKI模式下LAM mac地址读取

平台:RK3576 android14。

因为从android13开始,过GMS认证。需要改成GKI模式。vendor storage初始化没有完成,这就导致了之前用来读取MAC地址的方法不可用。

先看看非GKI模式下,读取MAC地址的流程。

 

我们MAC地址是通过RK的工具写入到vendor分区,然后在通过 rk_vendor_read 来读取出来,在驱动里面设置LAN 的mac地址。

我们使用的驱动是SDK里面的r8168驱动。具体路径为kernel-6.1/drivers/net/ethernet/realtek/r8168。

具体流程为: rtl8168_init_one 函数初始化时候会调用到 rtl8168_get_mac_address 来获取MAC地址。

 

static int
rtl8168_get_mac_address(struct net_device *dev)
{
        struct rtl8168_private *tp = netdev_priv(dev);
        int i,ret;
        u8 mac_addr[MAC_ADDR_LEN];

        for (i = 0; i < MAC_ADDR_LEN; i++)
                mac_addr[i] = RTL_R8(tp, MAC0 + i);

        if (tp->mcfg == CFG_METHOD_18 ||
            tp->mcfg == CFG_METHOD_19 ||
            tp->mcfg == CFG_METHOD_20 ||
            tp->mcfg == CFG_METHOD_21 ||
            tp->mcfg == CFG_METHOD_22 ||
            tp->mcfg == CFG_METHOD_23 ||
            tp->mcfg == CFG_METHOD_24 ||
            tp->mcfg == CFG_METHOD_25 ||
            tp->mcfg == CFG_METHOD_26 ||
            tp->mcfg == CFG_METHOD_27 ||
            tp->mcfg == CFG_METHOD_28 ||
            tp->mcfg == CFG_METHOD_29 ||
            tp->mcfg == CFG_METHOD_30 ||
            tp->mcfg == CFG_METHOD_31 ||
            tp->mcfg == CFG_METHOD_32 ||
            tp->mcfg == CFG_METHOD_33 ||
            tp->mcfg == CFG_METHOD_34 ||
            tp->mcfg == CFG_METHOD_35) {
                *(u32*)&mac_addr[0] = rtl8168_eri_read(tp, 0xE0, 4, ERIAR_ExGMAC);
                *(u16*)&mac_addr[4] = rtl8168_eri_read(tp, 0xE4, 2, ERIAR_ExGMAC);
        } else {
                if (tp->eeprom_type != EEPROM_TYPE_NONE) {
                        u16 *pUshort = (u16*)mac_addr;
                        /* Get MAC address from EEPROM */
                        if (tp->mcfg == CFG_METHOD_16 ||
                            tp->mcfg == CFG_METHOD_17 ||
                            tp->mcfg == CFG_METHOD_18 ||
                            tp->mcfg == CFG_METHOD_19 ||
                            tp->mcfg == CFG_METHOD_20 ||
                            tp->mcfg == CFG_METHOD_21 ||
                            tp->mcfg == CFG_METHOD_22 ||
                            tp->mcfg == CFG_METHOD_23 ||
                            tp->mcfg == CFG_METHOD_24 ||
                            tp->mcfg == CFG_METHOD_25 ||
                            tp->mcfg == CFG_METHOD_26 ||
                            tp->mcfg == CFG_METHOD_27 ||
                            tp->mcfg == CFG_METHOD_28 ||
                            tp->mcfg == CFG_METHOD_29 ||
                            tp->mcfg == CFG_METHOD_30 ||
                            tp->mcfg == CFG_METHOD_31 ||
                            tp->mcfg == CFG_METHOD_32 ||
                            tp->mcfg == CFG_METHOD_33 ||
                            tp->mcfg == CFG_METHOD_34 ||
                            tp->mcfg == CFG_METHOD_35) {
                                *pUshort++ = rtl8168_eeprom_read_sc(tp, 1);
                                *pUshort++ = rtl8168_eeprom_read_sc(tp, 2);
                                *pUshort = rtl8168_eeprom_read_sc(tp, 3);
                        } else {
                                *pUshort++ = rtl8168_eeprom_read_sc(tp, 7);
                                *pUshort++ = rtl8168_eeprom_read_sc(tp, 8);
                                *pUshort = rtl8168_eeprom_read_sc(tp, 9);
                        }
                }
        }

        if (!is_valid_ether_addr(mac_addr)) {
                netif_err(tp, probe, dev, "Invalid ether addr %pM\n",
                          mac_addr);
                eth_random_addr(mac_addr);
                dev->addr_assign_type = NET_ADDR_RANDOM;
                netif_info(tp, probe, dev, "Random ether addr %pM\n",
                           mac_addr);
                tp->random_mac = 1;
        }
        rtl8168_hw_address_set(dev, mac_addr);
        rtl8168_rar_set(tp, mac_addr);

        /* keep the original MAC address */
        memcpy(tp->org_mac_addr, dev->dev_addr, MAC_ADDR_LEN);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
#endif
        return 0;
}

我们需要在  rtl8168_hw_address_set 前通过 rk_vendor_read 读取写入到vendor分区的MAC地址就可以。

正常非GKI模式,一般改到这里就可以实现读取vendor分区的mac地址了。

 

但是GKI模式下,cat sys/class/net/eth0/address 发现刷写的MAC并没有生效。 报错log如下:

rtl8168_get_mac_address: rk_vendor_read eth mac address failed (-1)

这是因为 GKI模式下 vendor storage初始化没有完成。

rk_vendor_read 的函数在 kernel-6.1\drivers\soc\rockchip\rk_vendor_storage.c 里面有定义。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/soc/rockchip/rk_vendor_storage.h>

static int (*_vendor_read)(u32 id, void *pbuf, u32 size);
static int (*_vendor_write)(u32 id, void *pbuf, u32 size);

int rk_vendor_read(u32 id, void *pbuf, u32 size)
{
	if (_vendor_read)
		return _vendor_read(id, pbuf, size);
	return -1;
}
EXPORT_SYMBOL(rk_vendor_read);

int rk_vendor_write(u32 id, void *pbuf, u32 size)
{
	if (_vendor_write)
		return _vendor_write(id, pbuf, size);
	return -1;
}
EXPORT_SYMBOL(rk_vendor_write);

int rk_vendor_register(void *read, void *write)
{
	_vendor_read = read;
	_vendor_write =  write;

	return 0;
}
EXPORT_SYMBOL(rk_vendor_register);

bool is_rk_vendor_ready(void)
{
	if (_vendor_read)
		return true;
	return false;
}
EXPORT_SYMBOL(is_rk_vendor_ready);

MODULE_LICENSE("GPL");

 可以看到通过外部申明有read的时候,才会有接口调用。通过代码跟踪,发现在非GKI模式下,rk_vendor_read 是在 kernel-6.1\drivers\soc\rockchip\sdmmc_vendor_storage.c 下有注册调用。

static int vendor_init_thread(void *arg)
{
	int ret;
	unsigned long timeout = jiffies + 3 * HZ;

	g_vendor = kmalloc(sizeof(*g_vendor), GFP_KERNEL | GFP_DMA);
	if (!g_vendor)
		return -ENOMEM;

	do {
		ret = emmc_vendor_storage_init();
		if (!ret || time_after(jiffies, timeout))
			break;
		/* sleep wait emmc initialize completed */
		msleep(100);
	} while (1);

	if (!ret) {
		ret = misc_register(&vender_storage_dev);
		rk_vendor_register(emmc_vendor_read, emmc_vendor_write); // 这里注册调用
	} else {
		kfree(g_vendor);
		g_vendor = NULL;
	}
	pr_info("vendor storage:20190527 ret = %d\n", ret);
	return ret;
}

 而在GKI模式下  vendor_storage 是没有初始化的,所以 rk_vendor_read 不会走这条路径,在GKI模式下是在  ram_vendor_storage.c 里面注册调用

static int ram_vendor_storage_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device_node *node;
	struct resource res;
	int ret;
	phys_addr_t size, start;

	if (g_vendor)
		return -EINVAL;

	node = of_parse_phandle(np, "memory-region", 0);
	if (!node)
		return -ENOMEM;

	ret = of_address_to_resource(node, 0, &res);
	if (ret)
		return ret;

	ret = -EINVAL;

	size = resource_size(&res);
	start = res.start;
	if (size != VENDOR_PART_SIZE << 9 || (start & (PAGE_SIZE - 1)))
		goto un_reserved;

	g_vendor = ram_vendor_stroage_map(start, size);
	if (IS_ERR(g_vendor))
		goto un_reserved;

	if (g_vendor->tag != VENDOR_HEAD_TAG)
		goto un_remap;

	misc_register(&vender_storage_dev);
	rk_vendor_register(ram_vendor_read, NULL); // 这里注册调用

	return 0;

un_remap:
	vunmap(g_vendor);
un_reserved:
#ifndef MODULE
	free_reserved_area(phys_to_virt(start), phys_to_virt(start) + size, -1, "memory-region");
#endif
	g_vendor = NULL;

	return ret;
}

 

通过询问RK工程师,需要修改DTS。ram_vendor_storage.ko才能加载配备上。完整的补丁如下:

diff --git a/kernel-6.1/arch/arm64/boot/dts/rockchip/pb-rk3576-android.dtsi b/kernel-6.1/arch/arm64/boot/dts/rockchip/pb-rk3576-android.dtsi
old mode 100644
new mode 100755
index 4e6574156dc..c7b953b6efe
--- a/kernel-6.1/arch/arm64/boot/dts/rockchip/pb-rk3576-android.dtsi
+++ b/kernel-6.1/arch/arm64/boot/dts/rockchip/pb-rk3576-android.dtsi
@@ -55,6 +55,11 @@
 			ftrace-size = <0x00000>;
 			record-size = <0x14000>;
 		};
+
+		vendor_storage_rm: vendor-storage-rm@00000000 {
+        	compatible = "rockchip,vendor-storage-rm";
+        	reg = <0x0 0x0 0x0 0x0>;
+    	};
 	};
 };
 
diff --git a/kernel-6.1/arch/arm64/boot/dts/rockchip/pb-rk3576-evb.dtsi b/kernel-6.1/arch/arm64/boot/dts/rockchip/pb-rk3576-evb.dtsi
old mode 100644
new mode 100755
index 7de1f286fcd..53869b62df2
--- a/kernel-6.1/arch/arm64/boot/dts/rockchip/pb-rk3576-evb.dtsi
+++ b/kernel-6.1/arch/arm64/boot/dts/rockchip/pb-rk3576-evb.dtsi
@@ -187,6 +187,12 @@
 		WIFI,poweren_gpio = <&gpio2 RK_PC7 GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
+
+    vendor_storage: vendor-storage {
+        compatible = "rockchip,ram-vendor-storage";
+        memory-region = <&vendor_storage_rm>;
+        status = "okay";
+    };
 };
 
 &bus_a72 {
diff --git a/kernel-6.1/drivers/net/ethernet/realtek/r8168/r8168_n.c b/kernel-6.1/drivers/net/ethernet/realtek/r8168/r8168_n.c
old mode 100644
new mode 100755
index 3a247a6e165..08c00337d94
--- a/kernel-6.1/drivers/net/ethernet/realtek/r8168/r8168_n.c
+++ b/kernel-6.1/drivers/net/ethernet/realtek/r8168/r8168_n.c
@@ -55,6 +55,7 @@
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
 #include <linux/ipv6.h>
 #include <net/ip6_checksum.h>
+#include <linux/soc/rockchip/rk_vendor_storage.h>
 #endif
 #include <linux/tcp.h>
 #include <linux/init.h>
@@ -119,6 +120,7 @@
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
    The RTL chips use a 64 element hash table based on the Ethernet CRC. */
 static const int multicast_filter_limit = 32;
+u8 eth1_mac_addr[6] = {0,0,0,0,0,0};
 
 static const struct {
         const char *name;
@@ -25427,7 +25429,7 @@ static int
 rtl8168_get_mac_address(struct net_device *dev)
 {
         struct rtl8168_private *tp = netdev_priv(dev);
-        int i;
+        int i,ret;
         u8 mac_addr[MAC_ADDR_LEN];
 
         for (i = 0; i < MAC_ADDR_LEN; i++)
@@ -25498,6 +25500,30 @@ rtl8168_get_mac_address(struct net_device *dev)
                 tp->random_mac = 1;
         }
 
+		// modified by asw
+		for(i=0;i<6;i++){
+			ret = rk_vendor_read(LAN_MAC_ID, eth1_mac_addr, 6);
+			if (ret != 6 || is_zero_ether_addr(eth1_mac_addr)) {
+				printk("%s: rk_vendor_read eth mac address failed (%d)",
+							__func__, ret);
+				eth_random_addr(eth1_mac_addr);
+				printk("%s: generate random eth mac address: %02x:%02x:%02x:%02x:%02x:%02x",
+							__func__, eth1_mac_addr[0], eth1_mac_addr[1], eth1_mac_addr[2],
+							eth1_mac_addr[3], eth1_mac_addr[4], eth1_mac_addr[5]);
+			}
+			msleep(100);
+		}
+
+		eth1_mac_addr[0] &= 0xfc;
+		printk("%s: eth mac address: %02x:%02x:%02x:%02x:%02x:%02x",
+				__func__, eth1_mac_addr[0], eth1_mac_addr[1], eth1_mac_addr[2],
+				eth1_mac_addr[3], eth1_mac_addr[4], eth1_mac_addr[5]);
+
+		for(i=0;i<6;i++){
+			mac_addr[i] = eth1_mac_addr[i];
+		}
+		// end by asw
+
         rtl8168_hw_address_set(dev, mac_addr);
         rtl8168_rar_set(tp, mac_addr);
 

 

备注:

之前考虑过在uboot中读取MAC地址,然后通过cmdline 传递到内核,内核在解析cmdline。结果发现GKI模式下,__setup 这个宏无法使用(简直是坑啊)。非GKI模式下可以使用的。

u-boot/arch/arm/mach-rockchip/board.c的static int rockchip_set_ethaddr(void)里,当定义了CONFIG_ROCKCHIP_VENDOR_PARTITION 时(默认应该的打开的)会获取工具写入的mac。

这里简单记录如下:

diff --git a/u-boot/arch/arm/mach-rockchip/board.c b/u-boot/arch/arm/mach-rockchip/board.c
old mode 100644
new mode 100755
index 60786f0e513..8c0dc73e0c1
--- a/u-boot/arch/arm/mach-rockchip/board.c
+++ b/u-boot/arch/arm/mach-rockchip/board.c
@@ -105,6 +105,26 @@ __weak int rk_board_init(void)
 
 #define MAX_ETHERNET	0x2
 
+static int rockchip_get_lan_mac(void)
+{
+#ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
+	char buf[ARP_HLEN_ASCII + 1];
+	u8 ethaddr[ARP_HLEN];
+	int ret,i;
+	
+	ret = vendor_storage_read(LAN_MAC_ID, ethaddr, sizeof(ethaddr));
+	if (ret > 0 && is_valid_ethaddr(ethaddr)) {
+		sprintf(buf, "%pM", ethaddr);
+		env_set("lan_mac", buf);
+	}
+#endif
+
+	for(i = 0;i<6;i++) 
+		printf("asw sss rockchip_get_lan_mac ethaddr[%d] = %2X\n",i,ethaddr[i]);
+	
+	return 0;
+}
+
 static int rockchip_set_ethaddr(void)
 {
 	__maybe_unused bool need_write = false;
@@ -112,9 +132,14 @@ static int rockchip_set_ethaddr(void)
 	char buf[ARP_HLEN_ASCII + 1], mac[16];
 	u8 ethaddr[ARP_HLEN * MAX_ETHERNET] = {0};
 	int i, ret = -EINVAL;
+	
+	printf("asw uboot rockchip_set_ethaddr\n");
 
 #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
 	ret = vendor_storage_read(LAN_MAC_ID, ethaddr, sizeof(ethaddr));
+	printf("asw rockchip_set_ethaddr ret = %d\n",ret);
+	for(i = 0;i<6;i++) 
+		printf("asw rockchip_set_ethaddr ethaddr[%d] = %2X\n",i,ethaddr[i]);
 #endif
 	for (i = 0; i < MAX_ETHERNET; i++) {
 		if (ret <= 0 || !is_valid_ethaddr(&ethaddr[i * ARP_HLEN])) {
@@ -143,9 +168,15 @@ static int rockchip_set_ethaddr(void)
 			env_set(mac, buf);
 		}
 	}
-
+	
+	for(i = 0;i<6;i++) 
+		printf("asw sss rockchip_set_ethaddr ethaddr[%d] = %2X\n",i,ethaddr[i]);
+	
 #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
 	if (need_write) {
+		
+		printf("asw need_write\n");
+		
 		ret = vendor_storage_write(LAN_MAC_ID,
 					   ethaddr, sizeof(ethaddr));
 		if (ret < 0)
@@ -153,6 +184,7 @@ static int rockchip_set_ethaddr(void)
 			       __func__, ret);
 	}
 #endif
+	printf("asw return rockchip_set_ethaddr \n");
 	return 0;
 }
 #endif
@@ -477,7 +509,10 @@ static void scan_run_cmd(void)
 
 int board_late_init(void)
 {
+	
+	printf("asw uboot board_late_init\n");
 #ifdef CONFIG_ROCKCHIP_SET_ETHADDR
+	rockchip_get_lan_mac();
 	rockchip_set_ethaddr();
 #endif
 #ifdef CONFIG_ROCKCHIP_SET_SN

 这里是通过 env_set("lan_mac", buf); 把mac地址传给cmdline了。然后在u-boot/arch/arm/lib/bootm.c里面作下处理就好了。补丁如下:

 

--- a/u-boot/arch/arm/lib/bootm.c
+++ b/u-boot/arch/arm/lib/bootm.c
@@ -232,7 +232,32 @@ 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[2048] = {0}; //注意这里,如何数组定义太小,cmdline会有缺失,然后导致系统不开机。
+       char* old_bootargs = env_get("bootargs");
+          
+          printf("asw boot_prep_linux old_bootargs = %s\n",old_bootargs);
+          
+       int old_len = strlen(old_bootargs);
+       char *lan_mac = env_get("lan_mac");
+          
+          printf("asw boot_prep_linux lan_mac = %s\n",lan_mac);
+
+       if(lan_mac){
+                  strncpy(new_bootargs, old_bootargs, old_len);
+                  sprintf(new_bootargs, "%s %s%s", new_bootargs, "lan_mac=", env_get("lan_mac"));
+                  env_set("bootargs", new_bootargs);
+                  printf("asw boot_prep_linux new_bootargs = %s\n",new_bootargs);
+       }
+       commandline = env_get("bootargs");
+           printf("asw boot_prep_linux commandline = %s\n",commandline);
+#else
+       char *commandline  = env_get("bootargs");
+#endif
+
+       // char *commandline  = env_get("bootargs");
+       printf("asw aaaa bootargs = %s\n",commandline);
 
        if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
 #ifdef CONFIG_OF_LIBFDT

 这样就可以在uboot阶段读取mac地址,然后传递给cmdline。格式为 lan_mac=xx:xx:xx:xx:xx:xx,这里我写入的 lan_mac=50:af:73:4a:c6:98

POS:/ # cat /proc/cmdline
console=ttynull stack_depot_disable=on cgroup_disable=pressure kasan.page_alloc.sample=10 kasan.stacktrace=off kvm-arm.mode=protected bootconfig ioremap_guard storagemedia=emmc console=ttyFIQ0 firmware_class.path=/vendor/etc/firmware init=/init rootwait ro loop.max_part=7 printk.devkmsg=on usbcore.autosuspend=-1 usbcore.quirks=325d:6410:k,21c4:0cd1:k,0951:1666:k,058f:6387:e usb-storage.quirks=174c:x55aa:f,152d:0583:f,0bc2:2321:u,05e3:0749:mr kvm-arm.mode=none 8250.nr_uarts=10 bootconfig lan_mac=50:af:73:4a:c6:98 earlycon=uart8250,mmio32,0x2ad40000 rcupdate.rcu_expedited=1 rcu_nocbs=all  fwver=ddr-v1.09-2f85f4b2d4,spl-v1.07,bl31-v1.14,bl32-v1.05,uboot-06/04/2025

 

这样就可以通过cmdline传递给kernel了。在kernel里面通过 __setup 宏解析出lan_mac地址,在r8168驱动里面添加如下代码可以获取mac地址:

 

diff --git a/kernel-6.1/drivers/net/ethernet/realtek/r8168/r8168_n.c b/kernel-6.1/drivers/net/ethernet/realtek/r8168/r8168_n.c
index 246613165f7..f52d0ecb4b5 100755
--- a/kernel-6.1/drivers/net/ethernet/realtek/r8168/r8168_n.c
+++ b/kernel-6.1/drivers/net/ethernet/realtek/r8168/r8168_n.c
@@ -117,6 +117,13 @@
 #define FIRMWARE_8168FP_3   "rtl_nic/rtl8168fp-3.fw"
 #define FIRMWARE_8168FP_4   "rtl_nic/rtl8168fp-4.fw"
 
+// modified by asw 
+#define LAN_MAC_STR_LEN 17 //e.g. AA:BB:CC:DD:EE:FF
+static unsigned char mac_addr_str[18]= {0};
+static char lan_mac_addr_hex[6] = {0};
+// end by asw 
+
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
    The RTL chips use a 64 element hash table based on the Ethernet CRC. */
 static const int multicast_filter_limit = 32;
@@ -25425,6 +25432,31 @@ rtl8168_hw_address_set(struct net_device *dev, u8 mac_addr[MAC_ADDR_LEN])
 #endif //LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0)
 }
 
+
+// modified by asw 
+static int __init get_lan_mac_addr(char* str)
+{	
+	printk("asw get_lan_mac_addr str=%s\n",str);
+	if(!strcmp(str,"<NULL>") || (LAN_MAC_STR_LEN != strlen(str))){
+		printk("lan_mac get failed\n");
+		return 0;
+	}
+	
+	strncpy(mac_addr_str,str, LAN_MAC_STR_LEN);
+	sscanf(mac_addr_str, "%02x:%02x:%02x:%02x:%02x:%02x", \
+	(int*)&lan_mac_addr_hex[0], (int*)&lan_mac_addr_hex[1], \
+	(int*)&lan_mac_addr_hex[2], (int*)&lan_mac_addr_hex[3], \
+	(int*)&lan_mac_addr_hex[4], (int*)&lan_mac_addr_hex[5]);
+	
+    return 0;
+}
+__setup("lan_mac=",get_lan_mac_addr);
+// end by asw 
+
 static int
 rtl8168_get_mac_address(struct net_device *dev)
 {

 之后就是替换 rtl8168_get_mac_address里面的mac地址就好了。

 

posted @ 2025-06-21 11:39  simple雨  阅读(342)  评论(0)    收藏  举报