Omapl138内存和外设分布图
从下图中的omapl138
top level memory map中可以看出:
DSP专用的内存空间有:
ARM专用的内存空间有:
Start.s代码分析
1.通过objdump可以查看编译好的反汇编代码,-S显示源代码和反汇编代码。
.globl _start
_start:
b reset c1080054<reset>
c1080000 ea000013
c1080000是程序加载的地址,在MAKEFILE中定义的。
c1080054是由reset的机器指令而产生与之对应的汇编指令。
ldr pc,_undefined_instruction
c1080004: e59ff014
ldr pc,[pc,#20];c1080020 <_undefined_instruction>
这句的意思是从当前跳转20个字节,执行_undefined_instruction。(再考虑到指令的流水线操作,要再加8,才是pc指向的位置)
.global _TEXT_BASE
_TEXT_BASE:
.word
CONFIG_SYS_TEXT(Uboot 被拷贝到DDR内存中的起始地址)
c1080000
下面是uboot中一些段的位置
_bss_start_ofs: 0x00053da0
_bss_end_ofs: 0x00092330
_end_ofs: 0x0005adf8
2.reset指令及相关代码会使CPU为SVC32mode,一边运行大多数的内核代码,禁止中断和快速中断。
3.宏定义:CONFIG_SKIP_LOWLEVEL_INIT(ARM926EJ-S基于ARMv5TE架构)这个宏定义在不同的boot loader中,状况是不一样的。它下面的函数:cpu_init_crit会运行一些非常底层的初始化过程。uboot分成了两部分,一部分叫second program loader,一部分叫uboot的主体部分。当程序把自己加载到主内存DDR中运行的时候,底层的这些初始化过程就已经做了,就不需要运行这些东西了。在片内SRAM中运行的那一小段bootloader会运行这段代码。(bootloard引导Linux的过程如下:CPU当中固化的ROM一段小代码把FLASH中关于bootloader的一小段代码加载到RAM中,然后再把bootloader的大部分代码加载到RAM当中去运行。)
cpu_inti_crit()函数的作用如下:
(1)
flush D Cache
(2)
invalidate TLB
(3)
invalidate I Cache
invalidate和flush的区别如下:
ICACHE中缓存了很多条的数据,一条数据可能缓存了128位,每当经过RAM读取或者运行一条指令,都会缓存到cache当中,CACHE中每条数据的最后设置了一个或者两个位,标明这个CACHE是有效还是无效,invalidate就是把所有的这些数据条的最后一位设置位无效,就不会再从CACHE中取了,而是从RAM中取,然后放在CACHE中。flush就是把数据全部清空。
(4)
disable MMU and D Cache, enable I Cache
4.
/* Set stackpointer in internal RAM to call
board_init_f */
call_board_init_f:
#ifdef CONFIG_NAND_SPL /* deprecated, use instead CONFIG_SPL_BUILD */(没有定义)
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#else
#ifdef CONFIG_SPL_BUILD(没有定义)
ldr sp, =(CONFIG_SPL_STACK)
#else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
#endif
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */汇编
ldr r0,=0x00000000
bl board_init_f
/* 跳转到board_init_f*/
顶层目录下:arch/arm/lib/board.c
为什么在调用C语言的函数之前要先设置好堆栈:
如果是汇编语言的跳转,把lr保存起来即可,但是如果是向c语言的跳转,不仅要保存lr,比如有一个函数func(int a, int b){
int c;
char b;
…
return;
}
c语言中设置好堆栈,把第一个局部变量放在r0中,第二个局部变量放在r1中,把多余的变量放在堆栈指针中,并进行下移。当把这些形参变量放完之后,把链接寄存器lr,放在紧接着的形参变量的下一个位置。然后开始放函数里面定义的哪些变量,在函数运行完之后,通过pop指令将这些函数里面定义的变量一个个弹出,指针就又指向了lr,然后把lr的值取出来,放回pc,就回到调用它的地方了。