操作系统移植(一)--启动分析

前言

从本节开始,开始讲述一些关于OS移植的内容;与Linux移植不同,本次讲的是嵌入式实时操作系统的移植,类似于ucos-ii这种,所以后面在说到任务抢占时,可能和熟知的Linux有所区别。

启动代码

众所周知操作系统的运行依赖于底层硬件环境,无论是Windows还是Linux,操作系统运行前的操作肯定是一系列初始化操作;自己装过Windows的人一定都见过一个叫BIOS的界面,在这里面为Windows分配系统盘,设置启动方式等。为什么要指定系统盘?我们开机后,计算机是如何从系统盘检测到操作系统而不是其他硬盘分区?在操作系统启动前,计算机还做了哪些事?这些就是本章将要讲述的内容。

startup.s

在操作系统运行前,都会先对CPU进行初始化操作,各个厂家都会提供类似于startup.s一类的文件,用于CPU初始化,也即启动代码。我们知道操作系统一般都是用C语音写的,但C语言的执行需要堆栈环境,CPU刚启动时,并没有分配堆栈区域,C语言是无法执行的,所以启动代码都是汇编实现的。

                PUBWEAK Reset_Handler
                SECTION .text:CODE:NOROOT:REORDER(2)
Reset_Handler
                LDR     R0, =SystemInit
                BLX     R0
                LDR     R0, =__iar_program_start
                BX      R0

如上代码,在startup.s文件中,会定义一系列中断,其中Reset_Handler是复位中断服务函数,即系统复位时执行的第一个中断,SystemInit是系统提供的初始化函数,CPU使用的时钟初始化操作,一般放在此处进行。__iar_program_start是编译器相关的,经过一些操作后,最终指向main()函数入口。
在操作系统移植时,根据处理器或操作系统要求,通常会修改Reset_Handler,例如添加中断向量表重定向操作,指定MSP(主堆栈指针)和PSP(进程堆栈指针)等。

                PUBWEAK NMI_Handler
                SECTION .text:CODE:NOROOT:REORDER(1)
NMI_Handler
                B       NMI_Handler

                PUBWEAK HardFault_Handler
                SECTION .text:CODE:NOROOT:REORDER(1)
HardFault_Handler
                B       HardFault_Handler

                PUBWEAK MemManage_Handler
                SECTION .text:CODE:NOROOT:REORDER(1)
MemManage_Handler
                B       MemManage_Handler

                PUBWEAK BusFault_Handler
                SECTION .text:CODE:NOROOT:REORDER(1)
BusFault_Handler
                B       BusFault_Handler

                PUBWEAK UsageFault_Handler
                SECTION .text:CODE:NOROOT:REORDER(1)
UsageFault_Handler
                B       UsageFault_Handler

                PUBWEAK SVC_Handler
                SECTION .text:CODE:NOROOT:REORDER(1)
SVC_Handler
                B       SVC_Handler

后面是其它的中断服务例程,操作系统移植时一般不需要修改,默认使用官方的就行。

中断向量表重定向

对于Cortex-M3系列的处理器来说,当中断产生时,默认是从0地址处查找中断向量表;但通常情况下,0地址处一般存放的是BOOT(例如U-BOOT)代码,用于系统运行前的相关配置操作。如果0地址处存放的是BOOT代码,当中断产生时,中断指针指向的就是BOOT,这样就会因为找不到相应中断服务例程,而产生异常。所以需要把中断向量表重定向,让中断产生时,从其他地址处查找中断向量表。

                PUBWEAK Reset_Handler
                SECTION .text:CODE:NOROOT:REORDER(2)
Reset_Handler
                mrs     r0, CONTROL
                orr     r0, r0, #0x2
                msr     CONTROL, r0
                isb

                ldr     r0, =SFE(CSTACK)
                msr     psp, r0

                LDR     R0, =__vector_table
                LDR     R1, =SCB_VTOR
                STR     R0, [R1]

                LDR     R0, =SystemInit
                BLX     R0
                LDR     R0, =__iar_program_start
                BX      R0

在上面的代码中

                LDR     R0, =__vector_table
                LDR     R1, =SCB_VTOR
                STR     R0, [R1]

SCB_VTOR是中断向量表重定向寄存器地址,__vector_table是重定向的地址,__vector_table在启动配置文件.icf中指定;添加这三步操作后,当有中断产生时,处理器就会从地址__vector_table处查找中断向量表。当然关于__vector_table也不是随意指定的,应合理划分存储器,防止因地址出错,而导致系统奔溃。

指定MSP/PSP

操作系统移植(一)--启动分析_第1张图片

C语言的运行,需要堆栈环境,通常栈生长方向向下的处理器,内存分配如上图所示。
在Cortex-M3系列处理器中,将SP(堆栈指针)分成了MSP和PSP两种。

  • MSP:主堆栈指针,用于操作系统系统内核以及异常处理例程(包括中断服务例程)
  • PSP:进程堆栈指针,用户的应用程序使用的堆栈

提供两种堆栈指针的目的是,将用户程序(或者说上层应用程序)的堆栈区域和操作系统的堆栈区域分开。为了防止用户程序的堆栈错误从而破坏OS的堆栈,致使OS奔溃,Cortex-M提供了两种堆栈供我们使用,MSP–主堆栈、PSP–进程堆栈。
Cortex-M复位时,默认操作系统和用户程序使用的是同一个堆栈区,为了防止上诉情况的发生,我们可以设置使OS的堆栈和用户程序的堆栈分开使用。让操作系统使用MSP,用户程序使用PSP,这样就可以避免因为用户程序的堆栈错误从而破坏OS的堆栈,致使OS奔溃。
操作系统使用的堆栈和用户程序使用的堆栈,可以理解为内核使用的堆栈和上层应用使用的堆栈,简单的可以理解为,开辟了两个堆栈区,用两个指针指向这两个区域。

                mrs     r0, CONTROL
                orr     r0, r0, #0x2
                msr     CONTROL, r0
                isb

                ldr     r0, =SFE(CSTACK)
                msr     psp, r0

CONTROL:控制寄存器,定义特权状态 ,并且决定使用哪一个堆栈指针

操作系统移植(一)--启动分析_第2张图片

通过向CONTROL控制寄存器写入不同值,可以决定使用哪个堆栈指针。SFE(CSTACK)是堆栈区域的地址。

总结

各处理器厂家,一般都会提供类似于 startup.s这种的启动文件,用于CPU初始化;但处理器厂家提供的一般都是通用或者示例代码,使用时要根据操作系统或具体的处理器做相应的修改。通常所做的操作就是指定堆栈指针、中断向量表重定向。
操作系统移植时,除了要修改启动文件外,还有一个至关重要的文件–配置文件.icf,用于指定内存分配。链接器 Linker 就是根据该文件来为变量分配对应的区域。.icf文件的作用及如何修改,在下面的文章将做解释。

你可能感兴趣的:(操作系统移植,操作系统,移植,嵌入式)