前言:
貌似不管用什么ARM处理器都会遇到一个问题,那就是MAC地址唯一性,如果是使用随机的,每次reboot之后MAC地址都会变化,如果是在代码里面固定死了,如果局域网里面有两个设备的话,路由又会有问题。其实最大的问题就是量产的不方便。
以前用stm32的时候,可以使用stm32的唯一ID来配置给MAC地址使用,后来使用的zynq并没有,然后就使用的是板子上的flash的以为ID。最近在研究imx6ull,也是同样的问题,查了一下datasheet之后发现这款CPU也有唯一ID。下面是datasheet里面的介绍:
接下来就切入正题了:
本篇blog不做过程分析,因为之前zynq已经分析过一次了,我已经知道需要在什么地方做修改了。所以接下来只把需要做修改的地方给大家分享一下,有需要看分析过程的朋友可以参考我之前写的blog:ZYNQ通过读取SPI Flash的唯一ID来做MAC地址使用。
首先依照惯例还是先介绍一下平台,这里使用的开发板是韦东山老师的100ask_imx6ull开发板,是真的便宜。然后u-boot和kernel都是百问网提供的。
然后说一下需要修改什么,主要是修改u-boot和设备树,跟kernel关系不大。
接下来先修改u-boot:
根据datasheet 《i.MX 6ULL Applications Processor Reference Manual》 2404页的寄存器介绍,可以知道只需要把这两个寄存器里面的ID读出来就行了。
然后这里会有两个ID,因为一共是64位,所以肯定采购一批IC的话,高32位因为是不会变的,所以我们需要知道哪个寄存器里面存的是低32位。因为我手里只有一张开发板,所以我麻烦了一下交流群里面的朋友把它的ID截图给我看了一下。
第一张的群里朋友的截图,第二章是我这边读出来的,所以可以确定我们应该使用OCOTP_CFG1寄存器里面保存的ID。
打开u-boot源码里面 ./cmd/fdt.c 找到函数 void set_working_fdt_addr(ulong addr) 将函数内容替换成
void set_working_fdt_addr(ulong addr)
{
void *buf;
/* patch by hlb start */
#define B2L(x) (((x & 0xff000000) >> 24) | ((x & 0xff0000) >> 8) | ((x & 0xff00) << 8) | ((x & 0xff) << 24))
unsigned int off_dt_struct; /* offset to structure */
unsigned int off_dt_strings; /* offset to strings */
unsigned int off_mem_rsvmap; /* offset to memory reserve map */
unsigned int temp;
unsigned int len;
unsigned int name_off;
unsigned char* str;
unsigned char* node_name;
int root_node = 0;
int mac_cnt = 0;
unsigned int ID0 = *((volatile const unsigned int*)0x21BC410);
unsigned int ID1 = *((volatile const unsigned int*)0x21BC420);
printf("\nID0 = 0x%08x\n", ID0);
printf("ID1 = 0x%08x\n", ID1);
/* patch by hlb end */
buf = map_sysmem(addr, 0);
working_fdt = buf;
/* patch by hlb start*/
#if 0
printf("addr = 0x%08x\n", addr);
printf("buf = 0x%08x\n", buf);
#endif
off_dt_struct = B2L(working_fdt->off_dt_struct);
off_dt_strings = B2L(working_fdt->off_dt_strings);
off_mem_rsvmap = B2L(working_fdt->off_mem_rsvmap);
#if 0
printf("off_dt_struct = %d\n", off_dt_struct);
printf("off_dt_strings = %d\n", off_dt_strings);
printf("off_mem_rsvmap = %d\n", off_mem_rsvmap);
#endif
off_dt_struct += (unsigned int)working_fdt;
off_dt_strings += (unsigned int)working_fdt;
off_mem_rsvmap += (unsigned int)working_fdt;
do
{
temp = *((unsigned int*)off_dt_struct);
off_dt_struct += 4;
temp = B2L(temp);
switch (temp)
{
case 1:
if (root_node == 0) //处理根节点
{
root_node = 1;
off_dt_struct += 4; //根节点没有名字,跳过
}
else
{
/* node name */
node_name = (unsigned char*)off_dt_struct;
//printf("node name: %s\n", str);
int str_len;
str_len = strlen((const char*)node_name) + 1;
off_dt_struct += str_len;
if (str_len % 4)
{
off_dt_struct += 4 - (str_len % 4); //4字节对齐
}
}
break;
case 2:
break;
case 3:
/* value len */
temp = *((unsigned int*)off_dt_struct);
len = B2L(temp);
off_dt_struct += 4;
/* nameoff */
temp = *((unsigned int*)off_dt_struct);
name_off = B2L(temp);
str = (unsigned char*)(off_dt_strings + name_off);
off_dt_struct += 4;
if (strstr((char*)str, (const char*)"local-mac-address"))
{
unsigned char* pmac;
pmac = (unsigned char*)off_dt_struct;
#if 1
printf("Finding eth%d node name is: %s\n", mac_cnt, node_name);
printf("Old local-mac-address value len = %d\n", len);
for (int i = 0; i < 6; i++)
{
printf("0x%02x ", pmac[i]);
}
printf("\n");
#endif
pmac[0] = 0x00;
pmac[1] = 0x0a;
pmac[2] = 0x35 + mac_cnt++;
pmac[3] = (unsigned char)(ID1 >> 16);
pmac[4] = (unsigned char)(ID1 >> 8);
pmac[5] = (unsigned char)(ID1 >> 0);
#if 1
printf("Use ID1 value!\n");
printf("local-mac-address value len = %d\n", len);
for (int i = 0; i < 6; i++)
{
printf("0x%02x ", pmac[i]);
}
printf("\n\n");
#endif
}
off_dt_struct += len; //加上value长度偏移
if (len % 4)
{
off_dt_struct += 4 - (len % 4); //4字节对齐
}
break;
case 9:
off_dt_struct = 0;
break;
default:
break;
}
} while (off_dt_struct);
/* patch by hlb end */
setenv_hex("fdtaddr", addr);
}
该函数里面主要是实现了解析设备树,然后找到MAC地址的属性,将MAC地址的低三个字节替换成UID的低三个字节。保存编译一下,到这里u-boot基本上就算改完了,然后接下来还要修改设备树,因为我这版设备树里面是没有MAC地址属性的。然后设备树解析这里也不详细赘述了,有兴趣的同学自行查阅资料,或者是去买韦东山老师的设备树视频来看一下。(其实这不是软文)
打开kernel源码 ./arch/arm/boot/dts 里的 100ask_imx6ull-14x14.dts 文件,找到:fec1 和 fec2 节点,然后添加:
local-mac-address = [00 0a 35 00 00 00];
最后编译一下dtb,通过nfs文件系统把dtb文件拷贝到开发板 /boot 目录下就行了,注意一下名字不要弄错了。最后再烧写一下u-boot。开机就能看效果了!
u-boot打印:
进入系统之后 ifconfig -a:
大功告成!
最后再罗嗦两句,第一个就是我是没钱买带TF卡版本的,所以我只有EMMC,然而用 mfg_tool 烧写EMMC的时候默认是 u-boot、kernel、dtb、rootfs 一起烧写的。然后这里只需要烧写 u-boot ,咨询了一下群里的老师,老师让修改一下烧写工具目录下的 ./Profiles/Linux/OS Firmware/ 里的 ucl2.xml 就行了。接下来查了一下资料,只需要删除一部分命令就行了:
大概就是把红色框框里面的东西删掉就OK了。具体语法不详细赘述了。
我把修改好的文件贴上来:
<!--
* Copyright (C) 2012, Freescale Semiconductor, Inc. All Rights Reserved.
* The CFG element contains a list of recognized usb devices.
* DEV elements provide a name, class, vid and pid for each device.
*
* Each LIST element contains a list of update instructions.
* "Install" - Erase media and install firmware.
* "Update" - Update firmware only.
*
* Each CMD element contains one update instruction of attribute type.
* "pull" - Does UtpRead(body, file) transaction.
* "push" - Does UtpWrite(body, file) transaction.
* "drop" - Does UtpCommand(body) then waits for device to disconnect.
* "boot" - Finds configured device, forces it to "body" device and downloads "file".
* "find" - Waits for "timeout" seconds for the "body" device to connect.
* "show" - Parse and show device info in "file".
-->
<UCL>
<CFG>
<STATE name="BootStrap" dev="MX6SL" vid="15A2" pid="0063"/>
<STATE name="BootStrap" dev="MX6D" vid="15A2" pid="0061"/>
<STATE name="BootStrap" dev="MX6Q" vid="15A2" pid="0054"/>
<STATE name="BootStrap" dev="MX6SX" vid="15A2" pid="0071"/>
<STATE name="BootStrap" dev="MX6UL" vid="15A2" pid="007D"/>
<STATE name="BootStrap" dev="MX7D" vid="15A2" pid="0076"/>
<STATE name="BootStrap" dev="MX6ULL" vid="15A2" pid="0080"/>
<STATE name="Updater" dev="MSC" vid="066F" pid="37FF"/>
</CFG>
<LIST name="SDCard" desc="Choose SD Card as media">
<CMD state="BootStrap" type="boot" body="BootStrap" file ="firmware/u-boot-imx6ul%6uluboot%_sd.imx" ifdev="MX6UL">Loading U-boot</CMD>
<CMD state="BootStrap" type="boot" body="BootStrap" file ="firmware/u-boot-imx6ul%lite%%6uluboot%_sd.imx" ifdev="MX6ULL">Loading U-boot</CMD>
<CMD state="BootStrap" type="load" file="firmware/zImage" address="0x12000000"
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6Q MX6D">Loading Kernel.</CMD>
<CMD state="BootStrap" type="load" file="firmware/zImage" address="0x80800000"
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6SL MX6SX MX7D MX6UL MX6ULL">Loading Kernel.</CMD>
<CMD state="BootStrap" type="load" file="firmware/zImage-imx6ul-%6uldtb%%ldo%.dtb" address="0x83000000"
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6UL">Loading device tree.</CMD>
<CMD state="BootStrap" type="load" file="firmware/zImage-imx6ul%lite%-%6ulldtb%%ldo%.dtb" address="0x83000000"
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6ULL">Loading device tree.</CMD>
<CMD state="BootStrap" type="jump" > Jumping to OS image. </CMD>
<!-- create partition -->
<CMD state="Updater" type="push" body="send" file="mksdcard.sh.tar">Sending partition shell</CMD>
<CMD state="Updater" type="push" body="$ tar xf $FILE "> Partitioning...</CMD>
<CMD state="Updater" type="push" body="$ sh mksdcard.sh /dev/mmcblk%mmc%"> Partitioning...</CMD>
<!-- burn uboot -->
<CMD state="Updater" type="push" body="send" file="files/u-boot-imx6ul%6uluboot%_sd.imx" ifdev="MX6UL">Sending u-boot.bin</CMD>
<CMD state="Updater" type="push" body="send" file="files/u-boot-imx6ul%lite%%6uluboot%_sd.imx" ifdev="MX6ULL">Sending u-boot.bin</CMD>
<CMD state="Updater" type="push" body="$ dd if=/dev/zero of=/dev/mmcblk%mmc% bs=1k seek=768 conv=fsync count=8">clear u-boot arg</CMD>
<CMD state="Updater" type="push" body="$ dd if=$FILE of=/dev/mmcblk%mmc% bs=1k seek=1 conv=fsync">write u-boot.bin to sd card</CMD>
<CMD state="Updater" type="push" body="$ while [ ! -e /dev/mmcblk%mmc%p1 ]; do sleep 1; echo \"waiting...\"; done ">Waiting for the partition ready</CMD>
<CMD state="Updater" type="push" body="$ mkfs.vfat /dev/mmcblk%mmc%p1">Formatting rootfs partition</CMD>
<CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk%mmc%p1"/>
<CMD state="Updater" type="push" body="$ mount -t vfat /dev/mmcblk%mmc%p1 /mnt/mmcblk%mmc%p1"/>
<!-- burn zImage -->
<CMD state="Updater" type="push" body="send" file="files/zImage">Sending kernel</CMD>
<CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk%mmc%p1/zImage">write kernel image to sd card</CMD>
<!-- burn dtb -->
<CMD state="Updater" type="push" body="send" file="files/zImage-imx6ul-%6uldtb%%ldo%.dtb" ifdev="MX6UL">Sending Device Tree file</CMD>
<CMD state="Updater" type="push" body="send" file="files/zImage-imx6ul%lite%-%6ulldtb%%ldo%.dtb" ifdev="MX6ULL">Sending Device Tree file</CMD>
<CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk%mmc%p1/imx6ul-%6uldtb%.dtb" ifdev="MX6UL">write device tree to sd card</CMD>
<CMD state="Updater" type="push" body="$ cp $FILE /mnt/mmcblk%mmc%p1/imx6ul%lite%-%6uldtb%.dtb" ifdev="MX6ULL">write device tree to sd card</CMD>
<!-- burn m4 demo bins-->
<CMD state="Updater" type="push" body="$ umount /mnt/mmcblk%mmc%p1">Unmounting vfat partition</CMD>
<!-- burn rootfs -->
<CMD state="Updater" type="push" body="$ mkfs.ext3 -F -j /dev/mmcblk%mmc%p2">Formatting rootfs partition</CMD>
<CMD state="Updater" type="push" body="$ mkdir -p /mnt/mmcblk%mmc%p2"/>
<CMD state="Updater" type="push" body="$ mount -t ext3 /dev/mmcblk%mmc%p2 /mnt/mmcblk%mmc%p2"/>
<CMD state="Updater" type="push" body="pipe tar -jxv -C /mnt/mmcblk%mmc%p2" file="files/rootfs_nogpu.tar.bz2" ifdev="MX6UL MX7D MX6ULL">Sending and writting rootfs</CMD>
<CMD state="Updater" type="push" body="frf">Finishing rootfs write</CMD>
<CMD state="Updater" type="push" body="$ umount /mnt/mmcblk%mmc%p2">Unmounting rootfs partition</CMD>
<CMD state="Updater" type="push" body="$ echo Update Complete!">Done</CMD>
</LIST>
<LIST name="eMMC" desc="Choose eMMC as media">
<CMD state="BootStrap" type="boot" body="BootStrap" file ="firmware/u-boot-imx6ul%lite%%6uluboot%_ddr%ddrsize%_emmc.imx" ifdev="MX6ULL">Loading U-boot</CMD>
<CMD state="BootStrap" type="load" file="firmware/zImage" address="0x80800000"
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6SL MX6SX MX7D MX6UL MX6ULL">Loading Kernel.</CMD>
<CMD state="BootStrap" type="load" file="firmware/%initramfs%" address="0x83800000"
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6SL MX6SX MX7D MX6UL MX6ULL">Loading Initramfs.</CMD>
<CMD state="BootStrap" type="load" file="firmware/zImage-imx6ul%lite%-%6uldtb%-emmc.dtb" address="0x83000000"
loadSection="OTH" setSection="OTH" HasFlashHeader="FALSE" ifdev="MX6ULL">Loading device tree.</CMD>
<CMD state="BootStrap" type="jump" > Jumping to OS image. </CMD>
<!-- create partition -->
<CMD state="Updater" type="push" body="send" file="mksdcard.sh.tar">Sending partition shell</CMD>
<CMD state="Updater" type="push" body="$ tar xf $FILE "> Partitioning...</CMD>
<CMD state="Updater" type="push" body="$ sh mksdcard.sh /dev/mmcblk%mmc%"> Partitioning...</CMD>
<!-- burn uboot -->
<CMD state="Updater" type="push" body="$ dd if=/dev/zero of=/dev/mmcblk%mmc% bs=1k seek=768 conv=fsync count=8">clear u-boot arg</CMD>
<!-- access boot partition -->
<CMD state="Updater" type="push" body="$ echo 0 > /sys/block/mmcblk%mmc%boot0/force_ro">access boot partition 1</CMD>
<CMD state="Updater" type="push" body="send" file="files/u-boot-dtb.imx" ifdev="MX6ULL">Sending u-boot.bin</CMD>
<CMD state="Updater" type="push" body="$ dd if=$FILE of=/dev/mmcblk%mmc%boot0 bs=512 seek=2">write U-Boot to sd card</CMD>
<CMD state="Updater" type="push" body="$ echo 1 > /sys/block/mmcblk%mmc%boot0/force_ro"> re-enable read-only access </CMD>
<CMD state="Updater" type="push" body="$ mmc bootpart enable 1 1 /dev/mmcblk%mmc%">enable boot partion 1 to boot</CMD>
</LIST>
</UCL>
注意!注意!注意!我这里是使用的EMMC哈!
然后说第二点,通过上面的修改,两个网卡的MAC地址都应该是搞定了的。然而这里面还有一种情况,就是 u-boot 的环境变量里面设置了 ethaddr 变量,这种情况下u-boot会去解析设备树之后把我们修改好的值替换成这个变量的值。当然这里也是可以解决的,解决方法就在上文中提到的另外一篇blog里面写得很详细的,因为我实在是不想打字了,抱歉了。
最后依照惯例还是应该要说一下,本人毕竟水平有限。有什么问题就联系我吧!