学习嵌入式系统刚刚开始,理论基础欠缺,所以导致在实际移植遇到问题比较难解决。想熟悉流程,先按照网上的一些介绍文章移植了u-boot,移植了2.4.21的内核。系统跑起来了,但是发现一个问题,简单的说就是eth0不可用,这样target board无法与server连通,nfs和tftp都是不可用的,以后的嵌入式软件移植不可能仅仅通过串口连接完成。所以必须解决这个问题,从网上搜索,没有发现有价值的东西。在CU上咨询,a-ki给我了很多好的建议,使得这个问题最终得到了解决。
---------------------------------
问题:u-boot从flash启动后ethaddr无效,导致eth0无效。
环境:移植到at91rm9200,u-boot的版本为 1.1.1
具体过程如下:
u-boot移植运行正常,过程就不叙述了。在u-boot运行正常的情况下,准备移植内核:
大体上的规划如下:
0x0000 0000
INTERNAL ROM(128K BYTES)
0x1000 0000(第0扇区)
boot.bin FLASH
0x1001 0000(第0扇区)
uboot.gz FLASH
0x1002 0000(第1扇区)
ulmage FLASH
0x1012 0000(第9扇区)
ramdisk FLASH
0x107E 0000(第63扇区)
u-boot环境变量 FLASH
0x2000 0000
SDRAM
0x2100 0000
ulmage SDRAM
0x2110 0000
ramdisk SDRAM
我采用的是第一种,在终端设定环境变量。具体如下:
u-boot>setenv ipaddr 192.168.1.100 #设定目标板ip
u-boot>setenv serverip 192.168.1.106 #主机ip
u-boot>setenv ethaddr 00:00:00:00:ff:01 #设定目标板mac地址
u-boot>saveenv #保存环境变量
u-boot>tftpboot 20000000 boot.bin #采用tftp协议,将boot.bin下载到20000000的SDRAM
u-boot>protect off 1:0 #除保护
u-boot>erase 1:0 #清除bank1的第0扇区
u-boot>cp.b 20000000 10000000 2984 #把boot.bin从ram复制到flash区10000000处,2984为boot.bin的大小(16进制)
u-boot>tftpboot 20000000 u-boot.bin.gz #同上
u-boot>cp.b 20000000 10010000 aacf
然后更换引脚,设为片外启动。断电重启,这是u-boot从flash开始引导,出现提示符,设定环境变量使过程自动化:
u-boot>setenv bootargs root=/dev/ram rw initrd=0x21100000,6000000 ramdisk_size=15360 console=ttyS0,115200 mem=32M
u-boot>setenv bootcmd tftpboot 21100000 ramdisk-rmk7\;tftpboot 21000000 uImage\;bootm 21000000
u-boot>saveenv
u-boot>run bootcmd
成功进入login提示,输入root,进入系统:
#ifconfig eth0 192.168.1.100
#ping 192.168.1.106
可以ping通。
接下来要固化到flash里面:
u-boot>setenv bootcmd tftpboot 21100000 ramdisk-rmk7\;tftpboot 21000000 uImage
u-boot>saveenv
u-boot>run bootcmd
u-boot>protect off 1:2-11
u-boot>erase 1:2-11
u-boot>cp.b 21000000 10020000 9c64f
u-boot>erase 1:12-60
u-boot>cp.b 21100000 10120000 5591e6
u-boot>setenv bootcmd cp.b 10020000 21000000 9c64f\;cp.b 10120000 21100000 5591e6\;bootm 21000000
u-boot>saveenv
重新上电后,顺利进入login,输入root进入,执行命令如下:
AT91RM9200DK login: root
[root@AT91RM9200DK /root]$ifconfig eth0 192.168.1.100
SIOCSIFFLAGS: Cannot assign requested address
[root@AT91RM9200DK /root]$ifconfig
[root@AT91RM9200DK /root]$ifconfig eth0 up
SIOCSIFFLAGS: Cannot assign requested address
[root@AT91RM9200DK /root]$
查看启动提示过程,发现:
eth0: Link now 10-HalfDuplex
eth0: AT91 ethernet at 0xfefbc000 int=24 10-HalfDuplex (00:00:00:00:00:00)
eth0: Davicom 9196 PHY (Copper)
也就是说mac地址没有写入,成为了00:00:00:00:00:00。
解决方案:a-ki提示:在9200开发板上外接的是一个PHY芯片 ,MAC是存在u-boot,或者是在linux里的。在u-boot里,有两种方式可以设定MAC地址。
一是通过终端设定环境变量:
U-Boot> setenv ethaddr 12:34:56:78:90:ab
这种方式,你可以人为的为每块板子设定不同的MAC地址。
二是可以在u-boot的include/configs/yourboard.h程序中做宏定义:
#define CONFIG_ETHADDR 12:34:56:78:90:ab
至于在linux里面MAC地址存在,当然可以是存在EEPROM里,但我想也应该是由程序读出来,然后由驱动构造成完整的以太网桢,再通过9200的MII接口写入PHY(如dm9161)后,由PHY来发出。不会象某些芯片会自动读入。
我在具体的实践中发现,这两种方案都不能把问题解决。更换了mac地址,这个时候还是在u-boot>提示符下更改的,仍然不成立。也就是说一旦写入flash,mac地址就全为零,无效。那么,能否直接在进入linux之后在修改mac地址,然后指定ip呢?经过实践,此方案可行。具体方法如下:
---------------------------------
在超级终端中启动linux后,以root身份登陆,执行下面语句:
#ifconfig eth0 hw ether 00:e0:4c:4d:8d:5f //此处是重新赋予mac地址
eth0: Setting MAC address to 00:e0:4c:4d:8d:5f //显示结果
#ifconfig eth0 //此处设置你的目标板的ip
#ifconig //查看设置内容
#ping -c 8 //ping 你的server,来检验一下
---------------------------------
问题总结:我觉得这里是u-boot和linux不一致的地方,具体的原理部分还不是很不清楚,该分歧的地方具体在那里有待研究。不过我觉得这里不是mac地址设置的问题。实验了一下,mac地址是可以随便设的。只不过在u-boot里面设定的ethaddr没有读到linux下面,使得其为00:00:00:00:00:00。所以需要重新设定mac地址。如果有人清楚的知道该问题的核心所在,请告诉我,呵呵,在此多谢了。我也会好好思考的。
---------------------
2006-08-23
补充:
解决方法二:
读代码,以及从网上查找得知,u-boot的网络驱动是没有问题的,只是在和Linux的配合上不太协调。可以将kernel的net驱动部分修改一下,指定一个默认的合法的mac地址。
我现在用的版本是Linux-2.4.27-vsr1
先修改驱动:
linux-2.4.27//drivers/at91/net/at91_ether.c
265
268 static void get_mac_address(struct net_device *dev) {
269 AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
270 char addr[6];
271 static char default_ether_addr[]={0x36,0xB9,0x04,0x00,0x24,0x80};
272 unsigned int hi, lo;
273
274
275 hi = regs->EMAC_SA1H;
276 lo = regs->EMAC_SA1L;
277 addr[0] = (lo & 0xff);
278 addr[1] = (lo & 0xff00) >> 8;
279 addr[2] = (lo & 0xff0000) >> 16;
280 addr[3] = (lo & 0xff000000) >> 24;
281 addr[4] = (hi & 0xff);
282 addr[5] = (hi & 0xff00) >> 8;
283
284 if (is_valid_ether_addr(addr)) {
285 memcpy(dev->dev_addr, &addr, 6);
286 return;
287 }
288
289
290 hi = regs->EMAC_SA2H;
291 lo = regs->EMAC_SA2L;
292 addr[0] = (lo & 0xff);
293 addr[1] = (lo & 0xff00) >> 8;
294 addr[2] = (lo & 0xff0000) >> 16;
295 addr[3] = (lo & 0xff000000) >> 24;
296 addr[4] = (hi & 0xff);
297 addr[5] = (hi & 0xff00) >> 8;
298
299 if (is_valid_ether_addr(addr)) {
300 memcpy(dev->dev_addr, &addr, 6);
301 return;
302 }
303
304 memcpy(dev->dev_addr,&default_ether_addr, 6);
305 }
然后修改:
linux-2.4.27/include/asm-arm/arch-at91rm9200/pio.h
找到static inline void AT91_CfgPIO_EMAC_MII(void)函数,并将其替换如下内容,然后重新编译内核。
static inline void AT91_CfgPIO_EMAC_MII(void) {
AT91_SYS->PIOA_PDR |= AT91C_PA16_EMDIO | AT91C_PA15_EMDC | AT91C_PA14_ERXER | AT91C_PA13_ERX1
| AT91C_PA12_ERX0 | AT91C_PA11_ECRS_ECRSDV | AT91C_PA7_ETXCK_EREFCK;
AT91_SYS->PIOB_PDR |= AT91C_PB25_EF100 | AT91C_PB19_ERXCK | AT91C_PB18_ECOL | AT91C_PB17_ERXDV
| AT91C_PB16_ERX3 | AT91C_PB15_ERX2;
AT91_SYS->PIOD_PDR |= AT91C_PD0_ETX0 | AT91C_PD1_ETX1 | AT91C_PD4_ETXEN | AT91C_PD2_ETX2
| AT91C_PD3_ETX3 | AT91C_PD5_ETXER;
AT91_SYS->PIOB_BSR |= AT91C_PB25_EF100 | AT91C_PB19_ERXCK | AT91C_PB18_ECOL | AT91C_PB17_ERXDV
| AT91C_PB16_ERX3 | AT91C_PB15_ERX2;
AT91_SYS->PIOD_BSR |= AT91C_PD2_ETX2 | AT91C_PD3_ETX3 | AT91C_PD5_ETXER;
}
完成后MII接口的网络可以使用,该驱动现在可以支持MII和RMII接口网络,这个需要在配置时选择,我现在用的是MII。写入flash启动后mac地址就显示为你所设定的mac地址了。
可以用diff制作一个补丁,方便使用。
---------------------