eCos系统的lwIP驱动存在一个bug,该bug导致用于数据发送同步的信号量计数值不断增长,当超出32位整数所能表示的最大值时将会从0xffffffff回滚到0,这时可能会导致lwIP协议栈核心线程永久挂起。

eCos官网:http://ecos.sourceware.org
eCos中文技术网:http://www.52ecos.net
eCos交流QQ群:144940146。
http://blog.csdn.net/zoomdy/article/details/19675089
mingdu.zheng<at>gmail<dot>com

后果

该bug引起的可能后果包括:

  1. 覆盖前一次发送数据,这可能会导致在网络上出现错误的数据包,在TCP/IP中,这不会产生多大影响,因为上层协议会保证数据的完整性和重发机制。
  2. 长时间连续运行后可能导致lwIP的核心线程进入永久等待信号量状态,进入这个状态后,lwIP基本上不再会有任何响应。

解决办法

修改io/eth/<version>/src/lwip/eth_drv.c源文件的eth_drv_send函数,将319行的if ((sc->funs->can_send)(sc) < 1)删除。

修改前的代码

#ifdef CYGFUN_LWIP_MODE_SEQUENTIAL
L318:    // Wait until we can send
L319:    if ((sc->funs->can_send)(sc) < 1)
L320:        cyg_semaphore_wait(&sc->sc_arpcom.send_sem);
L321:    if ((sc->funs->can_send)(sc) < 1)
L322:        CYG_FAIL("cannot send packet");
#endif // CYGFUN_LWIP_MODE_SEQUENTIAL

修改代码前信号量计数器在不断增长

修改后的代码

#ifdef CYGFUN_LWIP_MODE_SEQUENTIAL// Wait until we can sendcyg_semaphore_wait(&sc->sc_arpcom.send_sem);if ((sc->funs->can_send)(sc) < 1)CYG_FAIL("cannot send packet");
#endif // CYGFUN_LWIP_MODE_SEQUENTIAL

修改代码后,信号量计数值为1或0

lpc2xxx的硬件bug

LPC2XXX以及LPC176X等MCU的以太网控制器在硬件上存在一个bug,这个bug会导致系统复位后的第一个数据包发送完成后不会产生中断。在没有修复lwIP驱动之前,由于负负得正的神奇作用,这个bug不会导致失败,但是如果打开了eCos系统的断言选项,那么在将发送第二个数据包时引发断言;而在修复了lwIP驱动之后,这个bug反而起作用了,因此必须对lpc2xxx的硬件bug进行修复。如果仅修复lwIP驱动,那么lwIP将在尝试发送第二个数据包时进入永远等待信号量的状态;如果仅修复lpc2xxx,长时间运行后可能会进入永久等待信号量状态。

解决lpc2xxx的bug

lpc2xxx的bug仅在系统复位后第一次发送数据包时存在,因此修改lpc2xxx驱动的lpc2xxx_eth_send函数,如果是第一次发送数据包,那么做一次本来属于lpc2xxx_eth_deliver职责范围的工作——发送信号量。修改devs/eth/arm/lpc2xxx/<version>/src/if_lpc2xxx.c的lpc2xxx_eth_send函数。

修改前的代码

static void
lpc2xxx_eth_send(struct eth_drv_sc *sc,struct eth_drv_sg *sg_list,int sg_len,int total_len,unsigned long key)
{
L994:    cyg_uint32 tx_producer_idx;
L995:    cyg_uint32 tx_consumer_idx;
……
L1032:    priv->cur_tx_key = key;
L1033:    HAL_WRITE_UINT32(EMAC_TX_PROD_IDX, tx_producer_idx);
}

修改后的代码

static void
lpc2xxx_eth_send(struct eth_drv_sc *sc,struct eth_drv_sg *sg_list,int sg_len,int total_len,unsigned long key)
{
L994:    static cyg_bool silicon_bug_fixed = false;
L995:    cyg_uint32 tx_producer_idx;
L996:    cyg_uint32 tx_consumer_idx;
……
L1033:    priv->cur_tx_key = key;
L1034:    HAL_WRITE_UINT32(EMAC_TX_PROD_IDX, tx_producer_idx);
L1035:
L1036:    if(silicon_bug_fixed == false){
L1038:        silicon_bug_fixed = true;
L1039:        priv->tx_busy = false;
L1040:        _eth_drv_tx_done(sc, priv->cur_tx_key, 0);}
}

bug产生原因

eCos系统中的lwIP包含4部分代码,分别为lwIP协议栈核心(位于net/lwip_tcpip/<version>/src/core和net/lwip_tcpip/<version>/src/api)、lwIP协议栈与操作系统相关的部分(位于net/lwip_tcpip/<version>/src/ecos)、独立于硬件的驱动部分(位于io/eth/<version>/src/lwip)、硬件相关的驱动部分(位于devs/eth目录下,与具体使用的网卡控制器有关,这里以lpc2xxx的网卡控制器为例)。

lwIP有2种工作模式,一种为单线程模式,这种模式下所有协议栈核心代码及应用层代码必须在一个线程内;另一种为多线程模式,这种模式下协议栈核心将启动2个服务线程,应用层代码可以分布在不同的线程中。多线程模式更具有实用性,因此这里仅考虑多线程模式,单线程模式仅适用于网络功能简单且资源十分紧张的场合。

这里描述的bug存在于多线程模式下的独立于硬件的驱动程序中。在多线程模式下,eCos的lwIP驱动假设每次仅发送一个数据包,仅在前一个数据包发送完成后才能发送下一个数据包,这通过一个信号量来同步。lwIP协议栈核心线程调用eth_drv_send函数发送数据包并消费掉信号量。lwIP协议栈的另一个线程则处理以太网控制器的中断事件,当检测到数据发送完成时调用eth_drv_tx_done,eth_drv_tx_done则生产信号量。这是一个典型的生产者消费者模型,因此使用信号量是没有问题的,正常情况下该信号量的计数值将为0或1,不会出现其它数值,信号量初始化时计数值被初始化为1。问题在于生产者eth_drv_tx_done生产信号量是无条件的,也就是每次检测到数据包发送完成,都会生产信号量,而消费者eth_drv_send消费信号量是有条件的,仅在当前正有数据在发送时才会消费信号量,如果没有数据正在发送那么不会消费信号量,这导致了信号量的生产和消费是不平衡的,生产的数量会多于消费的数量。这种不平衡导致的结果是信号量的计数值不再是0或1,而是一个递增的数值。

修改前的代码

#ifdef CYGFUN_LWIP_MODE_SEQUENTIAL
L318:    // Wait until we can send
L319:    if ((sc->funs->can_send)(sc) < 1)
L320:        cyg_semaphore_wait(&sc->sc_arpcom.send_sem);
L321:    if ((sc->funs->can_send)(sc) < 1)
L322:        CYG_FAIL("cannot send packet");
#endif // CYGFUN_LWIP_MODE_SEQUENTIAL

这最终导致一些问题,比较常见的情况是当sc->sc_arpcom.send_sem信号量的计数值大于1时且当前正在发送数据包且未发送完成的情况下又要调用eth_drv_send函数发送数据,L319判断控制器是否可发送数据,这时控制器正在发送数据,因此返回结果是不可以发送数据,也就是if条件成立,执行L320的信号量等待语句。当sc->sc_arpcom.send_sem信号量的计数值大于等于1时,信号量等待语句消费掉一个信号量然后立即返回,本来是需要等数据发送完成后再返回的,现在的情况是立即返回了。导致的结果是在有数据正在的发送的情况下,又硬塞进来一个发送请求,这可能会破坏正在发送的数据包完整性,最终导致发送了错误的包。从L321和L322可以看得出来,如果eCos系统的断言可用,那么将会触发L322的断言。

比较极端的情况下将导致调用eth_drv_send的lwIP核心线程处于永远挂起状态。信号量计数值的范围是有限制的,超过这个范围将会引起数值溢出归零,eCos信号量的计数值为32位无符号整数,有效范围为0~0xFFFFFFFF。假设执行到L319时信号量计数值已经被累加到0xFFFFFFFF,如果这时产生了数据发送完成中断,然后系统切换到lwIP的另一个线程,该线程将调用eth_drv_tx_done函数,eth_drv_tx_done函数调用信号量的post函数,post函数对信号量计数值进行累加,0xFFFFFFFF加1的结果是为0!再切回lwIP核心线程时,信号量计数值已经变成了0,因此L320的信号量等待将会挂起直到信号量计数值大于0,问题是信号量计数值只有在数据发送完成时才会进行累加,而发送数据的线程已经挂起等待信号量,死定了!先进行条件检测,某种条件下进行等待,这是条件变量的用法。

eCos系统的lwIP驱动及lpc2xxx网卡驱动bug的解决办法相关推荐

  1. i217lm网卡驱动linux,【电脑不能上网怎么安装网卡驱动】i217lm网卡驱动xp

    当电脑因网卡驱动未正确安装而不能上网时,该如何更新与之匹配的网卡驱动程序呢?相信大家都会遇到这种情况,在没有驱动光盘的情况下,想要安装更新电脑的相关硬件驱动程序,就必须首先更新网卡驱动程序.今天小编就 ...

  2. (linux vm虚拟机网络连接失败,重启网卡失败原因及解决办法)

    linux vm虚拟机网络连接失败,重启网卡失败原因及解决办法 0 .vm虚拟机下的网络三种连接方式详解 1. vm虚拟机以及宿主机没有vmnet1 vmnet8 网卡 2 网卡配置文件出错 测试网络 ...

  3. win10安装账户卡住_关于解决win10装系统时创建帐户时卡住了的具体解决办法

    大家都知道,我们生活中离不开电脑,在使用电脑的过程可能就会碰到win10装系统时创建帐户时卡住了的问题,有不少对系统很了解的网友,也许都不太会解决这个win10装系统时创建帐户时卡住了的问题.如果你现 ...

  4. 笔记本重置找不到恢复环境_[绿茶u盘装系统]win10系统重置此电脑找不到恢复环境的解决办法...

    [绿茶u盘装系统]win10系统重置此电脑找不到恢复环境的解决办法 在win10专业版系统使用中,难免会遇到一些问题,一般我们会通过重置系统方式来解决一些解决不了的问题,但是有些win10用户反映,在 ...

  5. IOS8,IOS8.1等系统出现锁屏状态下WIFI断开问题的解决办法!

    IOS8,IOS8.1等系统出现锁屏状态下WIFI断开问题的解决办法! 参考文章: (1)IOS8,IOS8.1等系统出现锁屏状态下WIFI断开问题的解决办法! (2)https://www.cnbl ...

  6. IIS出现:“系统找不到指定的路径”问题的有效解决办法

    IIS出现:"系统找不到指定的路径"问题的有效解决办法 今天真的是悬!好吧我还是先讲述一下我的经理来诠释我现在心中的喜悦之情.昨天给公司的服务器装了一个beian.gov.cn推荐 ...

  7. win10系统打开文件安装软件总是弹出安全警告解决办法

    描述:win10系统打开文件安装软件总是弹出安全警告解决办法 步骤: win键+R,输入gpedit.msc 点击用户配置->管理模板->windows组件->附件管理器文件夹 找到 ...

  8. linux系统怎样安装驱动程序,linux下网卡驱动安装全过程

    方法一,用RPM包安装驱动程序方法: 1.将驱动程序文件bcm5700-.src.rpm复制到一个临时目录中,并在此目录中运行以下命令:rpm –ivh bcm5700-.src.rpm 2.运行以下 ...

  9. linux双网卡驱动配置,linux网卡驱动安装、双网卡绑定

    本次课程包含RAID0/1/5/6/10/50/60配置实验(使用Dell R720服务器实验).Redhat/CentOS/ubuntu/windows操作系统安装.windows/linux网卡绑 ...

最新文章

  1. 零基础学Python:一文看懂数字和字符串
  2. NYOJ 409 郁闷的C小加(三)
  3. 反射获取构造方法并使用【应用】
  4. telnet 功能启用并测试端口是否正常
  5. 改改Python代码,运行速度还能提升6万倍
  6. GetURL (java)
  7. 华为息屏显示鸿蒙系统动画,华为EMUI 11升级息屏UI和动画!升级点很像小米MIUI 12...
  8. 牛客网 java刷题_牛客网刷题(纯java题型 1~30题)
  9. php解析json里的hson_这种json字符串PHP如何解析?
  10. Linq 三表 left join 的实现
  11. C#-WinForm-打印控件
  12. 应届毕业生,只会抄代码,该怎么办?
  13. 台式计算机电源待机电流有多大,终于知晓电脑机箱电源12v多少安
  14. 安装sikuli报错:jnius/jnius_conversion.pxi:54:31: Casting temporary Python object to non-numeric non-Pyth
  15. excel求和怎么操作?这三个简单操作方法,轻松掌握
  16. 【修复H5农场复利】黄金家园农场理财游戏源码Thinkphp开发 带商城仓库商店模块
  17. AI实践之路:朴素贝叶斯
  18. 杭州将投放10万辆新一代互联网单车
  19. 软件加入使用时间_新人如何才能玩转时间机器字幕制作软件?时间机器字幕制作软件使用测评...
  20. MATLAB插值笔记

热门文章

  1. 联想笔记本X1开机报错0271:Check Date and Time setting,系统无限重启
  2. 基于MATLAB的水果分级设计
  3. 蚂蚁《c++.模拟》
  4. 爱心助农|百万斤丑苹果紧急待售!谁能帮这些特困孩子熬过寒冷冬天?
  5. 排列熵算法--用于时间序列信号的复杂度检测
  6. 计算机考证要到四级一共要多少钱
  7. 找规律/数位DP HDOJ 4722 Good Numbers
  8. 聚丙烯酰胺主要应用领域
  9. 走过的路-java源码阅读之路
  10. java方法调用之单分派与多分派(二)