跳至主要内容

博文

MIPS中断在uboot下的实现

摘要:本文阐述了MIPS中断在u-boot下的整个实现过程,并对实践中遇到的问题进行了分析,特别分析了u-boot所采用的位置无关代码及汇编实现的特殊性,对类似应用具有较好的借鉴意义。 随着Linux嵌入式系统的广泛使用,使用uboot作为bootloader越来越多。u-boot发源于ppc架构8xx系列,对ppc架构的支持最为完善,而对其它架构的支持情况则要弱一些,以MIPS为例,目前的最新版本u-boot-2010.03仍然不支持异常和中断的处理。缺少中断机制带来了一些麻烦,比如不能支持统一的点灯规范,更重要的是在无中断的单任务环境下,协议栈缺乏有效的超时重传机制,在复杂的框上环境中,单板容易假死在boot中。 本文描述了MIPS架构中断在u-boot下的实现过程,并对遇到的问题进行了分析和总结。我们首先讨论了通用的异常处理过程,然后结合代码实现对异常处理代码进行了阐述,最后对调试过程中出现的问题进行了分析。u-boot有其自身的特点,本文同时也对位置无关代码进行了一定的分析。 中断处理在实现上并不复杂,其处理过程可以简单地划分为下面几个步骤: 1. 保存中断上下文 2. 处理中断并应答 3. 恢复中断上下文 4. 使能中断 这种处理方式比较简单,整个中断处理是在中断环境中完成的,没有中断嵌套。对于VxWorks这样的实时操作系统,需要允许高优先级中断抢占低优先级中断,因此它的处理步骤要复杂一些,在进入中断后,只保存少量的易失性寄存器,并尽早地开启中断。因为我们只需要实现简单的定时器,所以就按照最简单的方法实现。 MIPS CPU产生中断时,CPU跳转到EBASE+0x180或者0x200(取决于COP0 Cause.IV的设置。IV=1时,中断使用0x200入口,IV=0时,中断使用通用异常入口0x180)处开始执行中断处理程序。一般来说,异常向量处的大小都是受限的,MIPS也不例外,每个异常向量的大小不能超过0x80的长度,如果要在这里进行上下文保存,空间是不够的。惯例是在这里设一处跳转,到一个大小不受限的地方开始保存上下文。 上下文的保存可以分为两种实现,一种是使用当前任务的栈,一种是使用专门的栈,对于只工作在内核态的boot来说,这两者在使用上并无差别。理论上,开辟专门的栈可靠性更高,不容易被破坏。对于不同的架构,上下文的含义不同,对MIPS而言,上下
最新博文

悼念

从未想到在我认识的人里有走得这么早的,惊闻一师兄杨志高在学校自杀,不由得悗惜。你让老师们如此钟爱,你的论文又让我们那样地景仰,你的人生为何却又如此短暂。 曾有一句话很认同,完美主义者等于失败者,真的没有事情可以做到完美。 愿你一路走好。

知识管理的原则

寻找PKM时,看到这样一个贴子,感觉有一些原则比较有启发作用,其实重要的是方法,其次是合适的工具。所谓原则,对不同人来说也不是绝对,适合自己的就好。 个人知识管理的29个原则(转) 1、持续的学习成为个人生存和发展的基础。持续学习不一定能带来成功,但不学习一定失败;  2、信息和知识爆炸,在一段时间和时期内,学习的内容必须聚焦。起码要在一个领域内成为专家。  3、你应该学习的内容取决于你的价值观、特长、个性和目标。  4、你必须学会如何有效的评估信息和知识,所以你必须根据你的价值观、特长、个性和目标确立自己对信息和知识的“过滤器”;  5、人是知识获取的重要渠道,所以你应该知道谁最擅长什么?遇到问题时知道可以向谁学习和请教;  6、你牛了你的朋友也一定牛,建立人际资源的基础是自己的知识基础、个性和激情、自己优势的合理展示和帮助别人的意愿;  7、人际关系需要维护;捷径是找到那些愿意共享自己朋友资源的人,你也应该做这样的人;  8、信息如果不经过处理,不能称为知识。所以你存储的知识起码你应该简单看过、知道是在讲什么;  9、信息和知识存储前应该尽可能做规范化的工作,例如你做的摘要、感触、觉得最有价值的部分、将来能做什么用等等;  10、建立自己的分类字典,而不是每次想起什么就建立什么样的文件夹或者标签。分类字典,持之以恒坚持,适当调整;  11、知识存储中分类不宜过宽,过宽则等于没有分类;分类不宜过深,过深后你就不会再去看;  12、充分利用各种工具,尤其是web2.0工具做知识存储和获取工作;  13、知识存储时适当共享,听取和收集别人的意见和建议;  14、有意识的做知识显性化的工作,既方便知识传播也促进知识学习和建立人际网络;  15、知识传播中必须考虑传播的方式和效率;  16、不能用简单朴素的语言表述的知识证明你还没有深入理解;  17、多用举例子、讲故事的方法传播你的知识、见解。这个过程是你对知识的再深化过程;  18、你的知识传播的越广,你的影响力越大;  19、你的目的决定了你知识利用的方式。如果目的是要写论文,则你的知识就是明确、简洁的表达;如果是想要在市场上销售,就必须产品化、规范化或者专利化;  20、知识本身没有价值,只有被利用时才能展现其价值;  21、知识必须跟任务、项目结合起来才能发挥作用;  22、单独的一个主题的知识很难被很好的利用,

VxWorks对中断的处理

我们平时使用intConnect调用挂接中断向量实际是将中断处理函数连接到vxworks内部的一个中断向量表,以MIPS为例,这个表为excBsrTbl,前几项与MIPS处理器的定义相同,但在后面保留了许多向量作为扩展使用。 intConnect为用户提供的回调函数与指针分配一小块内存(通过intHandlerCreate),并调用intVecSet将它设置到excBsrTbl中去。 intHandlerCreate用4条指令包装了用户函数,为原本不支持参数的中断处理函数提供了参数传递的功能。 FUNCPTR intHandlerCreate ( FUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ ) { FAST UINT * pCode; /* pointer to newly synthesized code */ pCode = (UINT *) malloc (sizeof (intConnectCode)); if (pCode != NULL) { /* copy intConnectCode into new code area */ bcopy ((char *)intConnectCode, (char *)pCode, sizeof (intConnectCode)); /* set the addresses & instructions */ pCode [0] |= HI_WORD (routine); pCode [1] |= HI_WORD (parameter); pCode [2] |= LO_WORD (routine); pCode [4] |= LO_WORD (parameter); } /* * Flush the cache so we don't get instruction * cache hits to wrong vector */ CACHE_TEXT_UPDATE ((void *) pCode, sizeof (intCo

container_of

Linux常用container_of宏从成员变量提取整个结构体的首地针,这个宏的定义如下: #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) typeof是gcc的一个扩展,用于确定一个变量的类型,有点像C++的RTTI,常用于表达式内的语句,在定义宏时,如果需要临时变量,可以这样做: #define max(a,b) \ ({ typeof (a) _a = (a); \ typeof (b) _b = (b); \ _a > _b ? _a : _b; }) 它可以保证我们定义的变量_a/_b与宏传入的变量a/b类型匹配,而不会产生编译器告警。 因此container_of的第一行就是定义一个与member类型匹配的变量__mptr,赋值后,__mptr为宏参数中的待转换指针,因为只是类型转换,不涉及数据读写,((type*)0)是没有任何副作用的。 第二行用__mptr减去member变量在type中的偏移,这样便可实际访问到ptr相同偏移,也即type的实际首地址了。offsetof有两种定义: #ifdef __compiler_offsetof #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) #else #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif __compiler_offsetof即__builtin_offsetof,__builtin_offsetof可能是gcc內建的支持(见gcc源码c-parser.c), 从后一种实现方式可以明显看到这一技巧,假定一个从0地址开始的结构体,取其成员member的地址正是结构体内的偏移。

低谷

近段时间,小猪的身体不好,连续好几个周末游走于各个医院,两人的心情也坏到了极点。现在的小猪已俨然成为一个药罐子,不再提当年之勇。这个周末又发起烧来,像一滩烂泥似地躺在床上,真是祸不单行。 而我呢,由于前任离职的缘故,现在出奇地忙,每天就像打仗似地,压得人喘不过气来,工作与家庭,真有些夹缝中求生存的感觉,两头都要兼顾,我想这一次我们是真的走到一个低谷了吧。 希望这一切都会过去,一切都能圆满地解决。

JTAG链路快速扫描方法

充分利用现有标准作为基础,是保证方案稳定而有效的一个原则。本文分析了IEEE1149.1协议,在与标准兼容的基础上,提供了一种快速扫描JTAG链路的方法。 根据 IEEE1149.1-2001 ,存在如下规则: 在 Test-Logic-Reset 状态下,测试逻辑被禁用,器件正常工作。 TAP 在下列条件下会进入 Test-Logic-Reset 状态:( a )上电,( b ) TRST 置低电平,( c )通过 TMS 与 TCK 迁跃状态。不论 TAP 当前的状态如何,在连续 5 个 TCK 的上升沿将 TMS 保持为高,即可使 TAP 进入 Test-Logic-Reset 状态。 每个设备都必须提供 BYPASS 指令,如果提供设备标志寄存器,则必须同时提供 IDCODE 指令。 在 TAP 的驱动下,进入 Test-Logic-Reset 状态后, IDCODE 指令必须在 TCK 下降沿被锁存到指令寄存器(如果设备不提供 IDCODE 指令,则锁存 BYPASS 指令)。所有 TAP 状态的切换必须在 TCK 的上升沿发生。 BYPASS 数据寄存器长度为 1 ,在 Capture-DR 状态下 TCK 上升沿,移位寄存器必须被设为 0 。 IDCODE 数据寄存器长度为 32 ,在 Capture-DR 状态下 TCK 上升沿,移位寄存器被设为设备标志码。设备 ID 数据寄存器最低位为 1 。 Manufacturer Identity 不可能为全 1 。根据 Rules 12.2.1 , 11 位的厂商代码分为两个部分: 7-1 位来自 EIA/JEP106 定义的代码的低 7 位(最高位为校验位), 11-8 位为连接码符总数目与 16 的模。目前尚不清楚厂商代码如何计算连接码,但是连接码定义为 7F ,因此 7-1 不可能为全 1 ,进而厂商代码不可能为全 1 。 00001111111 为无效的厂商代码,任何与 IEEE1149 兼容的设备都不使用该代码。 根据上述事实, JTAG 链扫描的方案设计如下: 连续产生 5 个 TCK ,并保持 TMS 为高,使 TAP 进入 Test-Logic-Reset 状态。 TDI 移入 1 位’ 1’ ,读取 TDO 。如果 TDO 为 0 转至第 3 步,