start.S详解学习(一):设置 CPU 模式

设置 CPU 模式

0-前置

/*
* armboot - Startup Code for ARM920 CPU-core
*
* Copyright (c) 2001 Marius Gr鰃er <mag@sysgo.de>
* Copyright (c) 2002 Alex Z黳ke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <gj@denx.de>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <version.h>
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start

1、globl关键字

globl是个关键字,对应含义为:

在这里插入图片描述
所以,意思很简单,就是相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全
局的,外部可以访问,所以,你可以看到:

u-boot-master\arch\arm\cpu\u-boot.lds

中,有用到此变量:

ENTRY(_start)

即指定入口为_start,而由下面的_start的含义可以得知,_start就是整个start.S的最开始,即整个uboot的代码的开始。

_start: b reset

_start后面加上一个冒号‘:‘,表示其是一个标号Label,类似于C语言goto后面的标号。
而同时,_start的值,也就是这个代码的位置了,此处即为代码的最开始,相对的0的位置。
而此处最开始的相对的0位置,在程序开始运行的时候,如果是从NorFlash启动,那么其地址
是0,

_stat=0

如果是重新relocate代码之后,就是我们定义的值了,即,在

u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\board\EmbedSky\config.mk

中的:

TEXT_BASE = 0x33D00000

表示是代码段的基地址,即_start=TEXT_BASE=0x33D00000

标签写为符号,后跟冒号“:”。然后,该符号表示活动位置计数器的当前值,例如,它是一个合适的指令操作数。如果使用相同的符号表示两个不同的位置,则会发出警告:第一个定义将替代任何其他定义。

2、ldr指令

而_start标号后面的:

b reset

就是跳转到对应的标号为reset的位置。

ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

LDR指令的格式为:

LDR 目的寄存器,<存储器地址>

LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。该指令在程序设计中比较常用,且寻址方式灵活多样,请读者认真掌握。

举个例子:
在这里插入图片描述
在这里插入图片描述
ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。

比如想把数据从内存中某处读取到寄存器中,只能使用ldr
比如:

ldr r0, 0x12345678 

就是把0x12345678这个地址中的值存放到r0中。

3、word

上面那些ldr的作用,以第一个_undefined_instruction为例,就是将地址为_undefined_instruction中的一个word的值,赋值给pc。

在这里插入图片描述
.word .word expr {,expr}… 分配一段字内存单元,并用expr初始化字内存单元(32bit)
在这里插入图片描述
所以上面的含义,以_undefined_instruction为例,就是,此处分配了一个word=32bit=4字节的地址空间,里面存放的值是undefined_instruction。

而此处_undefined_instruction也就是该地址空间的地址了。用C语言来表达就是:

_undefined_instruction = &undefined_instruction

*_undefined_instruction = undefined_instruction

在后面的代码,我们可以看到,undefined_instruction也是一个标号,即一个地址值,对应着就是在发生“未定义指令”的时候,系统所要去执行的代码。

(其他几个对应的“软件中断”,“预取指错误”,“数据错误”,“未定义”,“(普通)中断”,“快速中断”,也是同样的做法,跳转到对应的位置执行对应的代码。)

所以:

ldr pc, 标号1

。。。

标号1:.word 标号2

标号2:
	。。。(具体要执行的代码)

的意思就是,将地址为标号1中内容载入到pc,而地址为标号1中的内容,正好装的是标号2。
用C语言表达其实很简单:

PC = *(标号1) = 标号2

对PC赋值,即是实现代码跳转,所以整个这段汇编代码的意思就是:

跳转到标号2的位置,执行对应的代码。

4、balignl

.balignl 16,0xdeadbeef

balignl这个标号的语法及含义:

在这里插入图片描述
意思就是,接下来的代码,都要16字节对齐,不足之处,用0xdeadbeef填充。
其中0xdeadbeef其实没啥特别意思,就是要填充的内容,你把其换成其他的也行,当然最好也
和0xdeadbeef一样是4个字节。

/*
*********************************************************************
****
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*********************************************************************
****
*/
_TEXT_BASE:
	.word TEXT_BASE

此处和上面的类似,_TEXT_BASE是一个标号地址,此地址中是一个word类型的变量,变量名是TEXT_BASE,此值见名知意,是text的base,即代码的基地址,可以在

u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\board\EmbedSky\config.mk

中找到其定义:

TEXT_BASE = 0x33D00000
.globl  _armboot_start
_armboot_start:
	.word  _start

同理,此含义可用C语言表示为:

*(_armboot_start) = _start

在这里插入图片描述
关于_bss_start和_bss_end都只是两个标号,对应着此处的地址。

而两个地址里面分别存放的值是__bss_start和_end,这两个的值,根据注释所说,是定义在
开发板相关的链接脚本里面的,我们此处的开发板相关的链接脚本是:
u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\board\EmbedSky\u-boot.lds
其中可以找到__bss_start和_end的定义:
在这里插入图片描述
而关于_bss_start和_bss_end定义为.glogl即全局变量,是因为uboot的其他源码中要用到这两个变量,详情请自己去搜索源码。

在这里插入图片描述
关于FREE_RAM_END和FREE_RAM_SIZE,这里只是两个标号,之所以也是声明为全局变量,是因为uboot的源码中会用到这两个变量。

但是这里有点特别的是,这两个变量,将在本源码start.S中的后面要用到,而在后面用到这两个变量之前,uboot的C源码中,会先去修改这两个值,具体的逻辑是:

本文件start.S中,后面有这两句:

ldr pc, _start_armboot
_start_armboot: .word start_armboot

意思很明显,就是去调用start_armboot函数。

1-start_armboot函数

而start_armboot函数是在:
u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\lib_arm\board.c中:

b
即在start_armboot去调用了cpu_init。

2-cpu_init函数

cpu_init函数是在:

u-boot-1.1.6_20100601\opt\EmbedSky\u-boot-1.1.6\cpu\arm920t\cpu.c中

在这里插入图片描述
在cpu_init中,根据我们的一些定义,比如堆栈大小等等,去修改了IRQ_STACK_START ,FIQ_STACK_START ,FREE_RAM_END和FREE_RAM_SIZE的值。

至于为何这么修改,后面遇到的时候会具体再解释。

在这里插入图片描述
同上,IRQ_STACK_STARTFIQ_STACK_START,也是在cpu_init中用到了。

不过此处,是只有当定义了宏CONFIG_USE_IRQ的时候,才用到这两个变量,其含义也很明显,

只有用到了中断IRQ,才会用到中断的堆栈,才有中断堆栈的起始地址。快速中断FIQ,同理。

1-CPSR

  • CPSR 是当前的程序状态寄存器(Current Program Status Register),

  • SPSR 是保存的程序状态寄存器(Saved Program Status Register)。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

2-MRS

MRS - Move From Status Register

程序状态寄存器访问指令

/*
* the actual reset code
*/
reset:
	/*
	* set the cpu to SVC32 mode
	*/
	mrs r0,cpsr

在这里插入图片描述

3-bic

bic r0,r0,#0x1f

bic指令的语法是:

在这里插入图片描述

4-orr

orr r0,r0,#0xd3

在这里插入图片描述

5-msr

MSR - Move to Status Register

msr cpsr,r0

在这里插入图片描述
此行汇编代码含义为,将r0的值赋给CPSR。

在这里插入图片描述
在这里插入图片描述

感谢作者这么优秀的资料:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TrustZone_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值