djyos源码分析之initcpu.s文件分析

益力多3号 发表于 2018-2-27 17:20:02 | 显示全部楼层 [复制链接]
1 824
        此处使用的DJYOS源码均为V1.0.0版本下的,以DIYSTM32版本的代码为例:
        系统一复位,首先运行的是initcpu.s函数(对应在ST的文件夹目录下),先来分析一下这个文件。
        文件一开头就有以下的定义:
        IMPORT     |Image$$handle_msp$$ZI$$Limit|   
        IMPORT     |Image$$handle_msp$$ZI$$Base|     
        IMPORT     cpu_init                        
        IMPORT     load_preload

        首先,这里声明了Image$$handle_msp$$ZI$$Limit、Image$$handle_msp$$ZI$$Base,这两个是什么东西呢?这里需要用到SCAT文件的知识,Image是执行区的意思,Base:首地址,Limit:尾地址,我们可以看到在工程文件目录下的scatter目录下有两个文件,一个是debug.scat、release.scat,分别是debug版本和release版本下的链接文件,随便打开其中一个,都可以看到其下面有handle_msp +0 EMPTY 0x400这样的定义,初步可以看出,应该是执行区(关于加载区和执行区,请参考SCT文件相关资料)handle_msp零初始化数据段的地址,再打开工程的MAP文件,(双击工程),搜索Image$$handle_msp$$ZI$$Limit、Image$$handle_msp$$ZI$$Base,可以看到
                Image$$handle_msp$$ZI$$Base              0x2000bc00   Number         0  anon$$obj.o(handle_msp.bss)
                Image$$handle_msp$$ZI$$Limit             0x2000c000   Number         0  anon$$obj.o(handle_msp.bss)
        由此可以知道Image$$handle_msp$$ZI$$Base=0x2000bc00,Image$$handle_msp$$ZI$$Limit=0x2000c000,至于为什么是这两个数值呢?我们再回去看一下SCAT文件,我们发现handle_msp的偏移地址是0:+0,在handle_msp前面的一个执行区:heap_top,其地址是多少呢?heap_top 0x2000c000-0x400 EMPTY 0,其首地址是0x2000c000-0x400=0x2000bc00,大小是0,因为其大小是0,所以,handle_msp作为其相邻的执行区,其首地址应该与其一样是0x2000bc00,那么其尾地址自然等于其首地址加上其大小,所以=0x2000bc00+0x400=0x2000c000,这两个数值就可以得到了,接下来,还声明了两个函数cpu_init、load_preload,我们先不管这两个函数是干嘛用的,接着往下看:
                                        AREA        RESET, DATA, READONLY
                                        EXPORT      __Vectors
                                __Vectors
                                        DCD |Image$$handle_msp$$ZI$$Limit|
                                        DCD Reset_Handler
                                        DCD rst_fault_handler     ;nmi_fault_handler
                                        DCD rst_fault_handler     ;hard_fault_handler
        这里定义了一个__Vectors并把它放在RESET段,READONLY代表只读,也就是说放在FLASH区,也就是说在FLASH的最初的存储空间内存储了4个数值:Image$$handle_msp$$ZI$$Limit、Reset_Handler、rst_fault_handler、rst_fault_handler。Reset_Handler和rst_fault_handler是函数的地址。为什么是这四个数值呢?原来,CM3在复位的时候,默认(在不改变0xe000ed08的情况下)是在FLASH的起始位置把堆栈的栈顶指针读出来,赋给SP,然后在把第二个地址的数值读出来,赋给PC,所以,我们这里实际上是把Image$$handle_msp$$ZI$$Limit设为栈顶地址,Reset_Handler设为复位后第一个执行的函数,再接下来,我们可以看到以下代码:
                   AREA    |.text|, CODE, READONLY
                rst_fault_handler
                        nop
                        bx        lr

                        ENTRY
                Reset_Handler
                        ldr     r0,=|Image$$handle_msp$$ZI$$Limit|
                        msr     psp,r0                       
                        CPSID   I               
                        CPSID   F               
                        mov                r0,#0
                        msr                control,r0               

                        mov     r0,#0x20000000       
                        ldr     r1,=|Image$$handle_msp$$ZI$$Limit|
                        str     r1,[r0]
                        ldr     r1,=Reset_Handler
                        str     r1,[r0,#0x04]
                        ldr     r1,=rst_fault_handler
                        str     r1,[r0,#0x08]
                        str     r1,[r0,#0x0c]
                        str     r1,[r0,#0x10]
                        str     r1,[r0,#0x14]
                        str     r1,[r0,#0x18]
                        str     r1,[r0,#0x1c]
                        str     r1,[r0,#0x20]
                        str     r1,[r0,#0x24]
                        str     r1,[r0,#0x28]
                        str     r1,[r0,#0x2c]
                        str     r1,[r0,#0x30]
                        str     r1,[r0,#0x34]
                        str     r1,[r0,#0x38]
                        str     r1,[r0,#0x3c]

                        ldr     r1,=0xe000ed08     
                        str     r0,[r1]

                        bl      cpu_init        
                        bl      load_preload       
                        ALIGN
                        END
                       
        rst_fault_handler是错误处理函数,是一个死循环,Reset_Handler则是程序一复位首先会执行的函数,接下来重点分析一下Reset_Handler函数,
        ldr     r0,=|Image$$handle_msp$$ZI$$Limit|
        msr     psp,r0                       
        CPSID   I               
        CPSID   F               
        mov                r0,#0
        msr                control,r0       
        这几句的注释已经很清楚了,我们主要是看下面的代码,首先,把Image$$handle_msp$$ZI$$Limit的值存到地址为0x20000000的位置,再把Reset_Handler的值存到地址为0x20000004的位置,接下来就是初始化中断的向量表了,全部用rst_fault_handler函数进行初始化,然后再把r0的值0x20000000存进地址为0xe000ed08的位置,为什么要这样做
呢?原来,因为CM3在发生中断的时候是从0xe000ed08存储的数值指向的地方把前面所提到的中断向量表读出来的,这里把中断向量表存到RAM里的是为了可以方便修改,实际上后面也是通过往RAM里面写数值来修改这个向量表的。最后,跳转到cpu_init和load_preload中执行。
        最后再啰嗦一句,不知道大家有没有疑问,就是为什么initcpu.s是整个工程的启动文件而不是其他文件呢?也就是说为什么程序一上电之后就会跳到这个执行呢?
其实这个问题在前面已经解答过了,我们看一下SCAT文件就会明白,SCAT文件中有这样的定义:
                        ROM_LOAD 0
                        {
                                text_sysload 0
                                {
                                        initcpu.o (RESET, +FIRST)            ; Initialization code
                                        initcpu.o (+RO)
                                        * (+RO)
                                }
                                .
                                .
                                .
                        }
        也就是说,initcpu.s里面的RESET段是放在整个程序的最前面的,所以,__Vectors是放在整个FLASH的最前面的地址的,程序一上电,就会从FLASH的最前面的地址里把SP、PC指针取出来,然后就跳转到了Reset_Handler去执行了。本文件分析到此结束了,因个人水平有限,有错漏的地方还请务必指出,共同学习。



回复

使用道具 举报

发表于 2018-2-27 17:20:02 | 显示全部楼层
分析得很到位,但是你用的版本有些老了,为啥不用新版本呢?新版本会有很多新概念的。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

加入我们,

发现科技可以让生活更美好...

立即注册

如果您已拥有本站账户,则可

精华导读

推荐阅读

资讯排行

站点统计|手机版|小黑屋| 都江堰操作系统交流论坛 ( 粤ICP备11028047号 )

Templated By DJYOS 论坛  粤ICP备11028047号  

返回顶部 返回列表