目录
PowerPC
CPU不仅仅是一种计算资源,它为操作系统的实现提供了基本逻辑机制和物理支持。比如CPU可以提供特权态和用户态,以及迁移方法,为现代操作系统内核和用户程序权限的分离提供了基础。因此,想要深入理解Freertos的运行机制,需要了解相应的CPU架构。我们的项目中采用了NXP MPC57XX,即PowerPC架构。
PowerPC是IBM推出的精简指令集计算机。这里简单介绍一下对于CPU来说非常重要的两种资源—寄存器和异常处理。
常用寄存器
PowerPC 的应用级寄存器分为三类:通用寄存器(GPR)、浮点寄存器(FPR])和专用寄存器(SPR)。
需要特别注意的寄存器如下:
1,GPR中的R1寄存器在我们的系统中充当栈指针寄存器SP。
2,MSR CPU状态寄存器。
3,SPR 给出处理器核心内部资源的状态并对其进行控制
- 指令地址寄存器(Instruction Address Register,IAR),即PC寄存器。
它是当前指令的地址。IAR 主要是由调试器使用,显示将要被执行的下一条指令。*5746C芯片手册中没有该寄存器,需要调查与SRR0寄存器的关系。 - 链接寄存器(Link Register,LR)
这个寄存器存放的是函数调用结束处的返回地址。某些转移指令可以自动加载 LR 到转移之后的指令。每个转移指令编码中都有一个 LK 位。如果 LK 为 1,转移指令就会将程序计数器移为 LR 中的地址。而且,条件转移指令bclr
转移到 LR 中的值。 - 定点异常寄存器(Fixed-Point Exception Register,XER)
这个寄存器存放整数运算操作的进位以及溢出信息。它还存放某些整数运算操作的进位输入以及加载和存储指令(lswx
和stswx
)中传输的字节数。 - 计数寄存器(Count Register,CTR)
这个寄存器中存放了一个循环计数器,会随特定转移操作而递减。条件转移指令bcctr
转移到 CTR 中的值。 - 条件寄存器(Condition Register,CR)
详情请参见如下链接:
IBM Developer 正在整合其语言站点组合。 – IBM Developer
异常处理
操作系统的实现依赖于CPU所能提供的中断和异常处理机制。
PowerPC CPU提供了几种基本的中断类型(参见5746C芯片手册63章Exception小节),对于我们来说,比较常见的有Machine Check,External Input,System Call。
- Machine Check由CPU检测到某些系统错误时产生,比如非法访问,bus error。
- External Input就是我们所说的外部中断,我们系统中所配的CAN, Watch Dog, DMA, Uart,硬件定时器等中断都属于这种中断,实际上,Freertos的心跳也是外部中断,使用的是硬件定时器。
- System Call中断是软件产生中断的机制,一般在系统调用时使用,用来从用户态进入内核态,使用内核所提供的功能。Freertos的目前只有三个系统调用使用了System Call:vPortYield,xPortRaisePrivilege,vPortLowerPrivilege。从这里可以看出,Freertos很多的API并不是在内核上下文中执行,而是在调用Task本身的上下文中。
所以,可以把我们开发过程中遇到的中断大致分为两类。PowerPC CPU中断和外部中断。他们之间的关系是:外部中断是PowerPC CPU中断的一种。由此,我们也可以在我们的系统里找到两个中断向量表。
Power PC的CPU中断的处理函数定义在interrupt_vectors.S(core_exceptions_table)文件中。我们平常所配的外部中断,其中断向量表定义在startup_MPC5746C.S(intc_vector_table)文件中。
外部中断到来时,CPU先根据core_exceptions_table找到相应的处理函数,在该汇编函数中再通过查找中断向量表intc_vector_table,找到具体的处理函数,也就是一般我们定义的CAN,DMA,KL15等中断的处理函数。详细过程请参见第三章。
系统初始化和启动
本节的最终目的是理解RAM中的数据分布,和系统中各寄存器的作用和更新时机,以及Freertos中关键变量的作用和使用方法。
链接和存储分布
首先介绍一下在这一过程中涉及到的几个重点概念:GNU 链接脚本,init_table,zero_table,启动代码。
其中,链接脚本为linker_flash.ld文件,而init_table,zero_table,启动代码都存在于startup_MPC5746C.S文件中。
工程编译阶段,链接器会根据链接脚本的配置扫描所有源文件并进行如下动作
- 计算各SECTION在Flash和RAM中的位置。
- 根据上面的计算结果,对init_table、zero_table和其他一些记录SECTION地址的变量赋值。init_table和zero_table记录了启动时,需要拷贝到RAM中的SECTION在Flash和RAM的开始/结束地址。启动时,启动代码会根据这两个table将Flash中部分内容加载到RAM中。
- 指定启动代码的入口位置。
在我们的系统中,init_table主要指定了data SECTION(已初始化全局变量)和外部中断向量表在Flash和RAM中的地址。zero_table指定了bss SECTION,即未初始化全局变量在Flash和RAM中的地址。
由此可见,text SECTION,即代码段没有copy到RAM里面,所以我们的系统中,所有的代码都在Flash中执行。
链接脚本分析
GNU LD脚本简介:
GNU LD 脚本学习笔记 - windtail - 博客园
主要包含m_text, m_data两个地址段。这两个段规定了各数据结构在Flash和RAM中的地址,其中m_text段规定了Flash中的数据分布,m_data段规定了RAM中的数据分布
Flash |
说明 |
是否需要copy到RAM中 |
---|---|---|
cpu0_reset_vector | ||
cpu2_reset_vector | ||
startup | 记录启 |