RTEMS 4.9.4 csb337 bsp 的 start.S 分析

启动代码是应用程序中最先被执行的代码,初始化处理器和单板,使之可以执行接下来的~BSP~代码。
启动代码一般都是由汇编语言写成。为了使~C~语言多做一些初始化工作,并使整个初始化代码变得更易维护,
应尽量减少汇编语言的使用,只做一些必要的工作。
这些工作包括:


1 禁用所有可屏蔽中断;
2 用~0~填充未初始化数据段~.bss;
3 初始化~C~程序调用栈;
4 从~ROM~中将初始化数据拷贝到~RAM~中;
5 调用~boot_card~函数。


首先启动代码应禁用所有可屏蔽中断。刚开始执行操作系统的代码,还没有初始化操作系统的中断向量表,
处理器的中断向量表还可能是引导程序~(Bootloader)~中的地址。若没有禁用中断,结果很可能是整个初始化过程的失败。
如果处理器支持多种权限级别,必须让处理器工作在最高权限级别或管理状态下。否则,可能不能使用处理器的某些指令。
第二,启动代码用~0~填充未初始化数据段~.bss。第三,初始化~C~程序调用栈。
虽然汇编语言调用~boot_card~后不需要从该函数再返回,但~boot_card~需要调用其它的~C~函数。
这些函数需要正确返回,这些函数的局部变量都需要从栈中分配。所以,必须在汇编语言中安装~C~语言的调用栈。
当~RTEMS~启动多任务时,第一个任务的上下文会被切换到处理器上,处理器开始使用任务的栈。
当应用程序从~RTEMS~系统中退出时,该栈又会被切换回来。所以,这个调用栈的尺寸,应能支撑到~RTEMS~启动多任务。
第四,从~ROM~中将一些初始化数据拷贝到~RAM~中。这个操作是高度与处理器相关。
例如,基于~RTEMS~的应用程序烧写在处理器的闪存上,一些非~0~的全局变量需要初始化。必须从闪存中将初始化数据拷贝到全局变量所存储的位置~RAM~中。
注意,读者应区别常量全局变量,常量全局变量虽然也有初值,但存储在代码段,不需要初始化即有初值。
对于~Bootloader~直接加载~RTEMS~应用程序到~RAM~中的硬件环境,是不需要这个初始化步骤的。
Bootloader~加载操作系统的过程中,自然地将需要赋有初值的位置填充上指定的初值。
第五,直接调用~boot_card~函数,进入~C~语言撰写的初始化代码中,开始进一步的初始化。

下面以~csb337~的启动代码为例,分析~ARM~处理器上启动代码所作的工作。

1 关闭中断并进入管理模式~(SVC Mode);
2 用~0~填充未初始化数据段;
3 依次安装中断模式~(IRQ Mode)~的栈、快速中断~(FIQ Mode)~的栈、数据访问中止模式~(ABT Mode)~的栈、管理模式的栈;
4 初始化内存管理单元~(Memory Management Unit, MMU);
5 安装~ARM~的异常向量;
6 调用~boot_card~函数;
7 调用~bsp_reset~函数重新启动系统;
8 死循环,防止从~bsp_reset~函数返回。

第二步用~0~填充未初始化数据段,从~csb337~中链接脚本中可知,未初始化的数据段包括~.bss~段和栈的存储空间。

ARM~的内核一共有~7~种工作模式,其中系统模式~(SYS Mode)~和用户模式~(User Mode)~的栈是共用的。其余的工作模式每个模式一个栈指针。一共有~6~个栈指针。
RTEMS~内核和应用程序的代码执行在管理模式下,中断服务程序运行在中断模式或快速中断模式下,若发生数据访问错误的问题,即进入数据访问中止模式。
未定义指令中止模式~(UND Mode)、系统模式和用户模式都没有用到,所以只初始化了~4~个模式的栈指针。

初始化内存管理单元是与处理器相关的,并不是所有的~ARM~都具有~MMU。RTEMS~的应用程序实际上是一个进程,
所以~MMU~进行地址映射后实地址与虚地址是一致的。由于~ARM~处理器规定,异常向量存放的地址是~0x0。
通过~MMU,可以将内存中用于存放异常向量的地址变换为从~0x0~开始。通过查阅~MMU~地址映射表可知,代码将~0x200000~开始的~SRAM~映射为从~0x0~开始。
阅读过~at91rm9200~数据手册的读者知道,at91rm9200~从~0x0~开始的~1MBytes~存储空间是启动内存,可以通过寄存器将其映射为内部的~SRAM~或~ROM。
只是通过~MMU~这种方法比基于硬件配置这种方法更加通用。但同时我们也注意到,虽然通用,但是地址解析时需要访问~MMU,无形中增加了一些系统开销。

ARM~一共有~8~个异常向量。分别是复位、未定义指令、软件中断、预取指令中断、数据中断、保留、中断请求和快速中断请求~8~个。每个向量占~4~个字节,
但~4~个字节无法完成~4GB~空间的寻址跳转。所以,每个向量又多添加~4~个字节,用于组成~4GB~空间的寻址跳转。所以~ARM~的异常向量共占用~64~个字节。
代码将这~64~个字节向量表先用默认的向量表填充。在~boot_card~函数中,还会根据系统的要求修改相关的异常向量。

完成之后,启动代码调用~boot_card~函数开始后续的初始化。如果从~boot_card~函数返回,即调用~bsp_reset~函数重新启动整个系统。
当然,有些硬件环境不一定支持这么做。ARM~绝大部分处理器支持通过写相关寄存器复位系统,或通过操作看门狗复位系统。
如果硬件不支持软件复位,系统会进入调用~bsp_reset~之后的死循环。

你可能感兴趣的:(工作,汇编,存储,语言,任务,化工)