欢迎访问ic37.com |
会员登录 免费注册
发布采购

不同结构的芯片必须有对应的模式来适应操作系统的运行

日期:2021-3-19 (来源:互联网)

比如armv7,其操作系统的模式就是system模式,而且很容易切换到其他模式。要求清除bss段的原因是,由于c语言的语法规则,以前的存储程序的内存非常昂贵,所以程序在生成时,会将未初始化的全局变量和静态变量存入没有存入到内存空间的存储空间,然后在程序装载时,再将这些空间指向的区域清除。

由rt-thread系统移植到现在,已经积累了一些快速移植的经验,无论是已有的架构还是不同型号的芯片,只要按照一定的步骤来进行,就不会出现大的错误。下一步要做的就是解决效果不好的原因。

该移植的里程碑包括以下几个方面:1.芯片在正常模式下运行,c代码逻辑可以正常执行,2.至少有一个串口驱动3.上下文切换逻辑4.定时器可以正常使用5.正常中断会产生串口输入,并可以按照上面提到的顺序读取数据,详细说明问题和解决方案。

芯片如何工作

不同结构的芯片必须有对应的BZX55C12模式来适应操作系统的运行,这在芯片设计中是必须考虑的,因此移植也必须遵循这个原则。另外,还涉及到访问寄存器。比如armv7,其操作系统的模式就是system模式,而且很容易切换到其他模式。一般的armv8架构也具有el1权限级别。当然,也可以将晶片模式转换成其他模式,例如,rt-thread整个系统运行在el3特权模式下,它位于el3特权级别的最高层,但不是越高越好,而el3通常更适合使用。其切换逻辑通常在芯片启动、初始执行汇编代码逻辑、普通芯片上电之后,进入最高特权模式,切换到操作系统特定特权模式即可。

C代码可以正常执行

这一步也可以实现汇编代码,其中的主要操作是清除bss段并设置栈指针地址。要求清除bss段的原因是,由于c语言的语法规则,以前的存储程序的内存非常昂贵,所以程序在生成时,会将未初始化的全局变量和静态变量存入没有存入到内存空间的存储空间,然后在程序装载时,再将这些空间指向的区域清除。而函数中的非静态变量则存储在具有不确定地址的栈中。

如果不执行bss清零,则可能导致全局变量和静态变量的值不确定,从而使程序在编程时出现异常。清理bss段的步骤也很简单,把bss段的内存空间设置为0就可以了。并设置栈地址,也就是sp的地址,这样当操作系统线程还没有开始调度时,就可以获得最开始的栈空间。根据函数调用的c语言规则,c语言在进行函数调用时需要出栈和压栈,这部分栈空间是由用户自己分配的。所以,请注意,在rt-thread启动调度之前,还存在一个栈空间,它将不再被使用,并且在调度启动后,每个线程栈空间将生效。

最低限度的串口驱动。

要完成这项工作,需要注意的是,串口驱动的验证工作已经提前完成。也就是能够正常的发送数据。通过rt-thread串口驱动对接程序,只需实现串口的初始化,串口接收,串口发送,中断注册即可。由于前无中断,实现了串口发送功能后可继续下一步工作。一般情况下,可以看到串口输出rt-thread的logo。

上下文转换逻辑

对于程序,上下文可以被理解为程序正在运行的地方。其位置主要包含:所有当前寄存器状态、当前sp的值、某些处理器的pc值等等。

对于第一个被调度的线程,手动分配其上下文内容。因为不能保证调度器执行的第一个线程是哪个特定的线程,所以每个线程都存储一个人工填充的上下文。值得一提的是,启动第一个线程调度后,将出现全局中断,特别是在上下文恢复时,这将通过汇编代码实现。第二,当线程退出后,启动下一个调度,由空闲线程执行线程回收任务。三要保证出栈与压栈的顺序一致。

该功能实现的标志是main函数和msh控制台之间的正常连接。然而,由于没有实现串口输入中断,因此不能进行输入控制,如果已经实现了串口中断,那么可以使用msh输入。

定时装置正常

先验中断可以正常产生,定时器可以正常使用,然后定期产生定时器中断。定时器是系统tick的关键,没有定时器系统无法通过delay释放任务中的CPU资源,但是可以通过主动切换任务进行调度。对rt-thread的tickTime的适配度,这里解释为,一般适配10ms,对于主频较高的芯片,可以是1ms。通过FPGA对30mhz主频进行了测试,结果表明该系统不能正常工作。因为系统定时器经常出现中断,主频过低,造成程序延迟处理完成,再出现中断。

串口输入操作正常。

这个步骤可以作为移植程序的成功验证,尽管这个步骤的工作并不复杂,但是通常前一个步骤是不成功的,这会导致不理想的情况发生。举例来说,曾经帮助过一位客户的移植工作,发现中断处理标志在打开串口后,只能输入一个字符串而没有反应,后来查到中断处理标志并未清空。一般能正常输入输出,本系统基本移植成功。

移植工作的难点

其中,规划栈帧、上下文切换和中断处理是最困难的一步。根据实际移植经验,容易出错的地方通常是入栈和出栈的顺序不匹配,或者有些寄存器没有保存到栈中。这时,要检查寄存器是32位的还是64位的,这可能是因为这个小细节导致了对栈帧的偏移。还注意,当一个线程压栈时,必须压回一个函数,在线程退出之后,由于没有注意到这个细节,曾经也导致main函数退出后,系统运行一个异常。

这种复杂的设计就是对于中断的嵌套设计,通常是在一个中断中执行调度,而不是在切换线程的上下文中立即执行,这会破坏现场,而只是在所有中断执行完成后才进行切换。很明显,cortex-m在处理pendsv异常时,中断控制器一直在等待,直到其他高优先级中断处理完成,然后再去处理低优先级的pendsv。对于sparc这种设计,切换任务是通过trap异常实现的,而trap异常则优先于中断,也就是切换线程优先于中断,这在系统设计中是不合理的,在软件设计中,通常是通过设置中断嵌套的标志位,等待所有的中断都结束,然后切换上下文,当一个中断执行时,上下文就一定不能切换。

促进经验共享

移植rt-thread有几个要点,找到这些要点,就可以很顺利地确定方向和目标,并对每个要点都进行技术攻克,这是最快、最有效的方法。要移植不同的芯片架构,您需要非常熟悉这个芯片架构,以及rt-thread系统中最关键的底层代码。熟悉rt-thread底层代码通常并不难,从aarch64的rt-thread最小系统实现中读出两三天即可大致理解,而阅读芯片手册则要结合实际工作经验,弄清楚芯片的优先模式,看懂寄存器,基本上看懂汇编。有些处理器需要实现mmu才能正常工作,比如aarch64,甚至对于1:1的映射也必须实现mmu。