|
本帖最后由 糜恒博 于 2018-12-6 13:21 编辑
rt-boot QQ群:751088367
转眼间,距离楼主上次发布rt-uboot[https://www.right.com.cn/FORUM/thread-337363-1-1.html]已经两个月了,在对uboot做了一些魔改之后,我愈发觉得uboot作为一个古典单线程boot loader,存粹靠魔改使其变成充分利用多线程机制的boot loader是一个不明智的选择,所以,追随着前辈们的脚步,从上个月开始,我着手进行全新的多线程boot loader设计,其设计目标是:
1.实现串口终端、telnet/udp终端、http终端等多种接口;
2.实现基于中断及事件的外设驱动,充分利用多线程同步机制;
3.设计通用的网络驱动和协议栈,具备基本事件驱动和伪socket接口;
4.设计udp端口监视功能,实现无按键中断启动;
5.具备各层次抽象接口,可方便移植到armv7和v8平台上;
经过一个月以来努力奋战,这些设计目标已完成80%以上,整个系统已经非常有样子了,所以先来发个小预览版,后续版本将不日完工放出。
预览版源代码地址在:https://github.com/zhaohengbo/rt-boot 【目前只支持qca9533(我手里就这么一个开发板),但是接口都是通的,移植到其他soc甚至是mtk平台很容易】
预览版运行截图
由于我本身不太会设计html网页,所以新的web界面略微COPY了一下H大的UI,不知是否可行,如有任何不妥我将立刻撤回原来的版本,也希望有人能够提供美观的web UI给我
支持web控制台执行cgi脚本
支持使用网络工具中断启动(无需按复位键)
网络终端,可免TLL连接内置终端(兼容Windows、Linux nc工具)
同时支持Telnet终端
内置DHCP服务器,可以直接获取ip
使用lwip作为tcpip协议栈
基于SFUD的SPI FLASH驱动框架,写0.3MB/s,读4MB/s
支持启动OpenWRT等linux系统
rt-boot的bin文件由两部分拼接而成:第一部分是spl,用于初始化ram和解压缩真正的boot loader,这部分代码比较简单,各个平台设计也没有多少可重用性,因此直接使用u-boot mod的bootstrap部分(略作更改);第二部分就是真正的boot loader,这是整个设计的重点,使用了全新的设计
rt-boot是一个全新设计的多线程bootloader,它依然以rt thread作为内核,但我对其内核略做了一些修改使其能完美运行于重定位环境上(rt-uboot没有做这个修复,这是个遗留的小坑,有空我再补上),它使用finsh中的msh作为shell接口,同样我也对它做了一些修改使其能运行于重定位环境上,tcp/ip协议栈部分,我以lwip2.1.0版本为原型,通过大量修改使其能够运行与重定位和无c库的平台之上【旧版本:我以uip1.0为原型,设计了一个具备伪socket接口的轻量级协议栈,目前已经完工(预览版代码未包含socket部分,因为uip本身代码的限制,我觉得使用基于事件的API更方便)】,网卡驱动部分,我参考linux平台的ag71xx驱动,根据rt thread内核特点进行简化修改,重新设计了ag71xx平台的驱动,目前在qca9533上工作稳定。其他部分的代码,基本参考uboot的逻辑进行了重新编写,修复了很多uboot1.1.4代码原有的隐藏bug。
整个rt-boot分为三层逻辑,arch层、soc层和board层,各层之间调用关系为自上而下(不同于一般实现的自下而上),因为我觉得自上而下更能表现不同路由器之间的差异和关联。每一层根据运行的位置又分为重定位前和重定位后,两者之间通过arch层的重定位函数链接。
另外,根据mips架构特点及重定位函数的特殊性质,在网上其他开源calltrace代码基础上做了一些改动以适应重定向下的calltrace(这个功能实际开发rt-boot时候才发觉太有用了!),遗憾的是由于时间紧迫(答应我妈12月份以后专心准备中考了),所以没能实现symbol表的绑定。
目前整体系统运行良好,但是还是因为时间太短的原因,很多细节都没补充,但实际上补充这些细节已经只是个时间问题而没有技术难度了,目前spi和flash部分已经完毕,大体上只剩启动linux这部分代码了。除此之外,一些线程由于拥有一些全局变量,不适合同时启动多个副本,限制了其应用数量(比如shell),当然这其实是finsh、uip本身代码就存在的问题,解决方案是同ag71xx一样将数据打包绑定成线程的专属para指针,线程启动时malloc然后传入调用。
目前rt-boot已经使用lwip作为协议栈而不再使用uip,lwip已经是开源协议栈里面非常好的一个了,再往上可能就是bsd协议栈了,但是为了精简体积,uip版本的rt-boot我也会继续维护,其协议栈将更新为经过我重写的,支持多个interface、具备socket接口的uip plus。
【旧版本:整体rt-boot的技术瓶颈主要在网络协议栈上,uip由于本事应用范围限制,主要使用基于事件的api,这种api导致程序设计需要复杂的状态机,同时所有的应用也不得不绑定在一个单一线程上,整体运行效率受到影响。
但是对于rt-boot应用场合而言,移植lwip是不合算的(由于重定向的影响增加大量工作量),所以可以在uip整体逻辑框架上进行重新设计,大体思路如下:
在现有uip逻辑上把全局变量私有化,并分解成多个线程,利用链表进行维护,不同线程间以邮箱等机制通讯。增加tx_worker线程,在使用tcp协议发送大数据时进行分片发送和ack、rexmit事件处理。】
最后说一下编译方式,项目的编译方式同u-boot mod,部分tools工具缺失可以在uboot找到(host的程序、crc校验、image拼接、以及mips的重定位patch程序【改自uboot2018.11,编译方式相同】),另外这份源代码是boot loader的第二部分代码,第一部分的bootstrap是在u-boot基础上略作改动,我已经编译或一个版本上传到论坛,解压到rt-boot的spl目录下即可,对应uboot改动如下:
1.bootstrap_board.c下增加函数:
- extern void dcache_flush_range(u32 a, u32 end);
- void flush_dcache(ulong start_addr, ulong size)
- {
- u32 end, a;
- a = start_addr & ~(CFG_CACHELINE_SIZE - 1);
- size = (size + CFG_CACHELINE_SIZE - 1) & ~(CFG_CACHELINE_SIZE - 1);
- end = a + size;
- dcache_flush_range(a, end);
- }
复制代码 2.bootstrap_board_init_r函数中增加代码:
- flush_dcache((ulong)ntohl(hdr->ih_load), (ulong)destLen);
复制代码
由于中考真的是迫在眉睫,从12月份开始我可能真的是更新不动了,在此之前我应该能把定下的目标达成,但之后可能会暂停开发直到中考结束,把程序完整开源也是希望有志同道合又有编程能力的坛友一起帮忙,把细节完善,打造出一个完全开源、功能强大的多线程bootloader,毕竟,对于免费软件来说,开源和竞争能让其获得鲜活的发展力。
另外,项目遵循MIT协议[不造这样可不可以,不可以我再改],可以随意修改和优化甚至商用而不必提供源代码,但是我还是希望大家能够把改动和优化提交上来,这样才能促进rt-boot的不断进步,谢谢!
编译好的bootstrap文件:
编译好的bootloader:[请注意仅为技术预览,无实际恢复能力!]
补充:关于Web界面快速响应的原理与实现
使用过uboot_mod的坛友都知道,uboot_mod的web界面打开的异常缓慢,一些不死uboot提供的固件下载传输速度也仅能达到10-30KB/s,很多人都以为这是uboot单线程执行效率低而引起的,但最近在rt-boot上,我遇到了同样的问题,这令我很困惑,是什么原因导致这个问题的呢?
为了分析原因,我们使用wireshark抓包分析,抓包中我们可以看到,在整个传输过程中,pc和路由器维持在一个数据包一个ack的状态,但是,令人奇怪的是,pc的ack响应时间达到了数百ms之多,相比之下,路由器的ack连1ms都不到,难道是pc端处理延迟的问题吗?
但是通过trace分析,我发现pc端程序处理延迟低于1ms,看来不是pc端处理延迟的问题,难道是网络传输延迟的问题吗?很明显也不太可能,纯粹的推测分析到这里似乎陷入僵局,那么我们不如反过来,看看正常速度的传输是什么样子的:
我们可以看到,此时,pc与路由器发送处于路由器发送两数据包pc做一次ack的情况,此时pc的ack不再有延迟,很明显,就是这一点差别导致了传输速度的问题。
经过查阅资料,此种机制被称为延迟应答,即当接收端收到一个数据包后,会接着等待n个数据(一般的,n=1),然后一起发送ack除非等待计数器超时。uboot mod和rt-boot使用的tcpip协议栈实际上都是uip,uip为了简化复杂度对实现做了许多取舍,其中一个就是单个tcp连接需要等到上一个数据被接收端ack之后才会发送下一个数据,显然,这会让pc端等到计数器超时才发送ack,造成了访问延迟。
知道了问题的原因,我们就可以着手进行改进了:
一个解决方案就是禁用延迟应答,可以参考https://blog.csdn.net/wstoneh01/article/details/53333958
另一个解决方案是从uip下手,使其以支持延迟应答的方式发送数据,这需要uip具备主动poll conn的能力,当appcall发送完一个数据之后主动poll自己发送第二个数据包。对于rt-boot来说,可以通过向主循环强制发送poll唤醒事件来实现,同时uip_process需要加入新的事件flag和处理流程(详细见代码)。但是光具备主动poll能力是不够的,因为uip的原始的poll机制要求当前连接没有等待确认的数据,如果仅仅通过poll继续发送下一包数据,会造成数据帧的seq不发生改变(uip会在ack时更新),此时此数据帧就会被误认为是重传数据。这对uip协议栈改动较大,uip需要在发送数据时提前更新seq,同时又要通过ack时的接收seq校验,这部分代码目前还在进行稳定性测试,稍后会同步更新到rt-boot代码中。
经过这两种改动,我们可以再来测试一下rt-boot的web响应能力。
可以看到,此时,rt-boot亦能够支持延迟应答机制了,web界面可以做到极速响应,固件下载速度也突破了MB/s,撒花~
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
评分
-
查看全部评分
|