ARM-启动代码start.S
伪操作
-
汇编程序中以 . 开头的名称并不是指令的助记符,不会被翻译成机器指令,而是给汇编器一些特殊指示,称为汇编指示(Assembler Directive)或伪操作(Pseudo-operation),由于它不是真正的指令所以加个“伪”字。
1) .section指示把代码划分成若干个段(Section),程序被操作系统加载执行时,每个段被加载到不同的地址,操作系统对不同的页面设置不同的读、写、执行权限。
2).data段保存程序的数据,是可读可写的,相当于C程序的全局变量。本程序中没有定义数据,所以.data段是空的。 -
.section / .text
.text段保存代码,是只读和可执行的,表示后面那些指令都属于.text段。 -
.globl _start
(1)_start是一个符号(Symbol),符号:在汇编程序中表示一个地址。汇编程序经过汇编器的编译后,所有符号都会被替换成它之前所代表的地址值。
(2)在C语言中,我们通过变量名访问一个变量,其实就是读写操作对应地址上的内存空间,我们通过函数名调用一个函数,其实就是跳转到该函数第一条指令所在的地址(函数名即首地址),所以变量名和函数名都是符号,本质上都是代表内存空间的地址。
(3).globl是告诉汇编器,_start这个符号要被链接器链接到,所以要在目标文件的符号表中标记它是一个全局符号。_start就像C程序的main主函数一样特殊,是整个程序的入口。链接器在链接时会查找目标文件中的_start符号代表的地址,把它设置为整个程序的入口地址,因此每个汇编程序都要提供一个_start符号并且用.globl声明。如果一个符号没有用.globl声明,那么就表示这个符号不会被链接器用到。 -
_start:
这里定义了_start符号,汇编器在翻译汇编程序时会计算每个数据对象和每条指令的地址,当看到这样一个符号定义时,就把它后面一条指令的地址作为这个符号所代表的首地址。而_start这个符号又比较特殊,它所代表的地址是整个程序的入口地址,所以下一条指令b reset就成了程序中被执行的第一条指令。 -
b reset:
跳进(不再返回之前地址处)ARM的异常向量表。
.word(伪操作表示占4字节):8种异常分别占用4个字节,因此每种异常入口处都填写一条跳转指令,直接跳转到相应的异常处理函数中,reset异常是直接跳转到reset函数,其他7种异常则是用ldr将处理函数入口地址加载到pc中。
L1 I/D cache失效
1)什么是cache
- Cache 是位于 CPU与主存储器DRAM之间的少量超高速静态存储器 SRAM(static RAM),
其是为了解决 CPU 与主存之间速度匹配问题而设置。 - Cache又分为I-cache(用来存指令)和D-cache(用来存数据)
2)为什么要让cache失效
因为在使用cache的时候要经过一系列的初始化配置,cache在没配置之前是不能使用的。所以我们要关闭cache,但是在关闭cache之前cache里面可能已经有数据了,为了不影响我们的代码,所以要先让其失效,再进行关闭。
关闭MMU和cache
1) 什么是MMU:
MMU就是负责虚拟地址(virtual address)转化成物理地址(physical address)。
在这里肯定有人跟我一样的疑惑,既然有物理地址我们访问的时候访问物理地址不就完事了吗?为什么要有虚拟地址的存在,然后还要加个专门的硬件去转换,这就是多此一举吗?
其实加入了虚拟地址后有下面两个作用
- 虚拟内存:有了虚拟内存,可以在处理器上运行比实际物理内存大的应用程序。
- 内存保护:根据需要对特定的内存区块的访问进行保护,通过这一功能,我们可以将特定的内存块设置成只读、只写或是可同时读写。
2)为什要关闭MMU
跟cache的原因一样,在使用MMU之前要进行一系列的初始化,并且过程比较复杂,现在用不到MMU和cache,所以要关闭它们。
start.S代码注释
/*
* start.S
*/
/*
* Exception vector table:异常向量表b reset
*/
.text//伪操作
.global _start//声明一个_start全局符号
_start:
b 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
//异常处理函数
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq
/* The actual reset code,Exception vector table:异常向量表->复位代码 */
reset:
/* Set Vector Base Address Register:设置矢量寄存器基地址,重新映射异常向量表 */
ldr r0,=0x43c00000
mcr p15,0,r0,c12,c0,0 @ Vector Base Address Register
mrc p15, 0, r0, c1, c0, 0
bic r0, #(1<<13)
mcr p15, 0, r0, c1, c0, 0
/* Set the cpu to svc32 mode:将CPU设置为SVC模式10011,禁止fiq,irq则为1101 0011 = 0xd3 */
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
/* Enable NEON/VFP unit:使能NEON/VFP单元 */
mrc p15, #0, r1, c1, c0, #2
orr r1, r1, #(0xf << 20)
mcr p15, #0, r1, c1, c0, #2
mov r1, #0
mcr p15, #0, r1, c7, c5, #4
mov r0, #0x40000000
fmxr fpexc, r0
/* Cache init:高速缓存cache初始化 */
mrc p15, 0, r0, c0, c0, 0
and r1, r0, #0x00f00000
and r2, r0, #0x0000000f
orr r2, r2, r1, lsr #20-4
cmp r2, #0x30
mrceq p15, 0, r0, c1, c0, 1
orreq r0, r0, #0x6
mcreq p15, 0, r0, c1, c0, 1
/* Invalidate L1 I/D :让L1的I/D cache失效*/
mov r0, #0
mcr p15, 0, r0, c8, c7, 0
mcr p15, 0, r0, c7, c5, 0
/* Disable mmu stuff and caches :关闭MMU和cache */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000
bic r0, r0, #0x00000007
orr r0, r0, #0x00001000
orr r0, r0, #0x00000002
orr r0, r0, #0x00000800
mcr p15, 0, r0, c1, c0, 0
/* Initialize stacks:初始化栈 */
init_stack://栈满减
ldr r0, stacktop /*get stack top pointer:指向栈顶*/
/********svc mode stack********/
mov sp, r0 //将栈顶地址赋值给栈指针寄存器R13:sp
sub r0, #128*4 /*512 byte for irq mode of stack:将R0中的值减去128*4字节重新赋值给R0*/
/********irq mode stack********/
msr cpsr, #0xd2
mov sp, r0
sub r0, #128*4 /*512 byte for fiq mode of stack*/
/********fiq mode stack********/
msr cpsr, #0xd1
mov sp, r0
sub r0, #0
/********abort mode stack******/
msr cpsr, #0xd7
mov sp, r0
sub r0, #0
/********undefine mode stack**/
msr cpsr, #0xdb
mov sp, r0
sub r0, #0
/***sys mode and usr mode stack***/
msr cpsr, #0x10
mov sp, r0 /*1024 byte for user mode of stack*/
/******clear bss section:清除bss段********/
ldr r0, =__bss_start /* this is auto-relocated! */
ldr r1, =__bss_end__ /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l: cmp r0, r1 /* while not at end of BSS */
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
/* Call _main :跳进C:main主函数*/
b main
/*
* Exception handlers:异常处理函数
*/
.align 5 // align 5:表示2的5次方=32bit,也就是4字节对齐 = .word
undefined_instruction:
b . //跳转到当前文件中查找undefined_instruction的地址
.align 5
software_interrupt:
b .
.align 5
prefetch_abort:
b .
.align 5
data_abort:
b .
.align 5
not_used:
b .
.align 5
.global irq
irq:
sub lr, lr, #4
stmfd sp!, {r0-r12, lr}
.weak do_irq
@ bl do_irq
ldmfd sp!, {r0-r12, pc}^
.align 5
.global fiq
fiq:
sub lr, lr, #4
stmfd sp!, {r0-r12, lr}
.weak do_fiq
@ bl do_fiq
ldmfd sp!, {r0-r12, pc}^
stacktop: .word stack + 4 * 512 //栈顶
.data
stack: .space 4 * 512 //申请的栈空间大小