u-boot 1.1.6 start.S 代码学习<转>
———转自 http://blog.csdn.net/rockhard/article/details/4166642 ——————
/*
参考了别人的一些笔记,看完了启动代码。
本文档记录在看代码时碰到的困难,将这些曾经困扰的问题记录下来,以备今后之用。分析时不重要的代码被删除了。
*/
.globl _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
.balignl 16,0xdeadbeef
/*
_start是整个u-boot程序的入口点,即链接后,该处是整个程序的第一条指令。程序的入口点是由链接脚本所指定,比如对于smdk2410的板子(下面都以smdk241为例),脚本文件位于board/smdk2140/u-boot.lds。在该脚本文件中:ENTRY(_start) 即指定程序的入口地址。globl _start 定义一个外部可以引用的变量,比如说,在其它源代码文档中,就可以直指引用_start这个变量。如int entry=_start; 那此处entry值将是多少呢?因为_start相当于一个变量,entry的值就是_start处存储的值,即 b reset机器码值。关于globl定义的变量得注意的地方,后面还有记录
这段代码处理中断向量表。
关于 balignal 16,0xdeadbeef的网上资料:
.align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。
.balign的作用同.align。
.align {alignment} {,fill} {,max}
其中:alignment用于指定对齐方式,可能的取值为2的次幂,缺省为4。fill是填充内容,
缺省用0填充。max是填充字节数最大值,如果填充字节数超过max,就不进行对齐.
例如: .align 4, 指定对齐方式为字对齐
deadbeef一般用来表示没用的或是已经被释放掉的内存
*/
_TEXT_BASE:
.word TEXT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
/*
备注这几个由.word伪操作符定义变量的作用及其取值
_TEXT_BASE:
.word TEXT_BASE
_TEXT_BASE:此处定义一汇编语言标签,更好的理解就是:告诉编译器,为_TEXT_BASE分配存储空间,该空间的名字就叫_TEXT_BASE,该空间中存储的值就是由.word后面确定的TEXT_BASEC(即0x33F80000),相当于C语言中 long _TEXT_BASE=TEXT_BASE; TEXT_BASE定义在board/smdk2410/config.mk文件中。该值的作用是告诉链接器,本程序运行的基地址为TEXT_BASE。U-boot编译后,烧在FLASH的第一个块中,CPU复位上电后,PC寄存器为0x0000。怎么会跑到TEXT_BASE处执行呢?
事实上,CPU上电后,从地址0x0000处执行,而U-BOOT的最起始代码,即本文件中从_start开始的代码是与地址不相关的,这段代码放在任何空间执行的结果都是一样(当然不是绝对,假设u-boot代码段是100K,则放在TEXT_BASE-80K处,搬运时就会把u-boot代码后面20K部分覆盖为最前面的20K)。
.globl _armboot_start
_armboot_start:
.word _start
定义外部可以引用的变量_armboot_start,。即相当于C long _armboot_start=&_start; _armboot_start值是多少?是TEXT_BASE,即0x33F80000!等价的那条C语句,取的是_start变量地址,而不是_start本身。在C语言中,定义一变量 int x=100;就是告诉编译器。给我一个int大小的存储空间,该空间存储的值就是100,这个空间在哪呢?即空间地址是多少呢?我们可以通过&x知道。
在汇编语言中,理解上有点不一样。上面三行语句,
第一句,告诉编译器,向外面输出变量_armboot_start
第二句,_armboot_start变量在此处,到底在哪,要到链接时才能确定,凡正现在知道有这么一个变量了。
第三句,_armboot_start变量空间放的数据为_start标签的值。这点与C语言的理解有点不一样了。此处引用的是_start标签对应处的地址。在汇编语言中,标签代表的就是那行所在的地址。
图1是从u-boot编译后生成的u-boot.map截图的。从此文件中知道,_armboot_start这个变量地址为0x33f80044,
*/
图1
/*
.globl _bss_start
_bss_start:
.word __bss_start
此三句,特别要备注的是__bss_start这个符号,它的值为多少?该值定义在board/smdk2410/u-boot.lds文件中
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
上面的__bss_start=.; 表示__bss_start值就是当前位置的值。当前位置是多少呢?从下面一句
.bss:{*(.ss)}知道。紧接该位置后面马上就是放bss段数据了。所以,当然就是bss段的起始地址。_end就是bss段的结束地址。
参考:http://blog.chinaunix.net/u1/58780/showart_462971.html
bss是这个链接脚本的最后一个段。start.S就是以这个段的起始地址来计算要搬运u-boot大小的代码的。即,这个段前面的所有数据都将被搬到TEXT_BASE处。然后跑到start_armboot处,即C语言的入口代码。__bss_start这个值是多少? Smdk2410我编译后值是0x33f96f20。可以从图2的map文件中查到,bss段从0x33f96f20开始分配的。
再次验证一下0x33f96f20就是__bss_start值,我们可以从图1处可以看到有个变量_bss_start该变量就是由下面三条语句所定义,_bss_start处保存的值就是__bss_start:
.globl _bss_start
_bss_start:
.word __bss_start
用UltraEdit打开生成的u-boot.bin,定位到文件偏移0x48(0x48由_bss_start所在地址0x33f80048-TEXT_BASE得到),如图3,此处值确实是20 6F F9 33(注意大小端)
*/
图2
图3
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
/*
上面几行进入SVC模式,通过装入CPSR到r0,修改相应位后再载入到CPSR。
*/
/* turn off the watchdog 关闭WATCH DOG,具体寄存器地址看芯片DATASHEET即知*/
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
#endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR – default
* 设置中断屏蔽寄存器相应位,关闭中断。
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
/*
下面是重定位代码,即将整个u-boot搬到TEXT_BASE地址处的代码
/*
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
/*
adr r0, _start这句代码是将_start标签处运行时的地址值装进r0,这条指令到底取一个什么值呢?假设运行到该指令时pc寄存器的值是X,start标签相对此本指令有Y的偏移,则r0=X+Y(Y可能是负值).
针对该程序来说,当被装载到0x0000处运行时,r0就是0,假设装载到TEXT_BASE处运行,则r0=TEXT_BASE.
几条指令分析如下:
求正在运行的程序_start标签处地址到r0,将_TEXT_BASE变量值装到r1,即将0x33f80000装到r1,比较r0/r1是否相等,这个比较就是确定当前是不是从Flash中执行的,还是这段代码已装载到0x33f80000处执行的。如果不等于0x33f80000,则将FLASH中的u-boot代码搬到0x33f80000处。
具体计算如下:
ldr r2,_armboot_startàr2=0x33f80000
ldr r3,_ss_startàr3=bss段的起始地
*/
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
/*
上面几行将r0地址处的代码复制到r1处,即从0x0000搬到0x33f80000(假设CPU复位从0x0000执行的)。
*/
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/* Set up the stack 设置堆栈 */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
/*
上面代码中,指定从(TEXT_BASE - CFG_MALLOC_LEN)开始地址,大小为CFG_MALLOC_LEN的内存预留给由malloc函数。因为u-boot中其它地方调用了malloc函数,该空间就是供其动态分配的。
再向低端又预留了CFG_GBL_DATA_SIZE字节的数据(注:为global_data结构体预留的空间,看board.c)
然后为IRQ及FIQ中断预留空间,
最后将预留空间的低端地址赋给sp,ARM堆栈由低到高增长的??
*/
clear_bss: /*将bss段数据清零*/
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
/*下面一句跳到C语言的入口处start_armboot(函数定义在board.c中) */
ldr pc, _start_armboot
_start_armboot: .word start_armboot
/*关键代码分析结束*/
u-boot 1.1.6 start.S 代码学习<转>的更多相关文章
- u-boot代码学习内容
前言 u-boot代码庞大,不可能全部细读,只能有选择的读部分代码.在读代码之前,根据韦东山教材,关于代码学习内容和深度做以下预先划定. 一.Makefile.mkconfig.config.mk等 ...
- Objective-C代码学习大纲(3)
Objective-C代码学习大纲(3) 2011-05-11 14:06 佚名 otierney 字号:T | T 本文为台湾出版的<Objective-C学习大纲>的翻译文档,系统介绍 ...
- ORB-SLAM2 论文&代码学习 ——Tracking 线程
本文要点: ORB-SLAM2 Tracking 线程 论文内容介绍 ORB-SLAM2 Tracking 线程 代码结构介绍 写在前面 上一篇文章中我们已经对 ORB-SLAM2 系统有了一个概览性 ...
- ORB-SLAM2 论文&代码学习 —— 单目初始化
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要点: ORB-SLAM2 单目初始化 ...
- ORB-SLAM2 论文&代码学习 —— LocalMapping 线程
转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12360913.html 本文要点: ORB-SLAM2 Local ...
- Learning Memory-guided Normality代码学习笔记
Learning Memory-guided Normality代码学习笔记 记忆模块核心 Memory部分的核心在于以下定义Memory类的部分. class Memory(nn.Module): ...
- 3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习
3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习 Hello小崔 华为技术有限公司 Linux内核开发 2 人赞同了该文章 LTP代码学习方法主要介绍两个步骤, ...
- Apollo代码学习(七)—MPC与LQR比较
前言 Apollo中用到了PID.MPC和LQR三种控制器,其中,MPC和LQR控制器在状态方程的形式.状态变量的形式.目标函数的形式等有诸多相似之处,因此结合自己目前了解到的信息,将两者进行一定的比 ...
- spring boot中利用mybatis-generator插件生成代码
使用Idea在spring boot中集成mybatis-generator,自动生成mapper.xml model dao 文件 一.配置 pom.xml 在pom.xml的<plugi ...
- 一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式
前言 有时候我们需要在应用启动时执行一些代码片段,这些片段可能是仅仅是为了记录 log,也可能是在启动时检查与安装证书 ,诸如上述业务要求我们可能会经常碰到 Spring Boot 提供了至少 5 种 ...
随机推荐
- 微信小程序+腾讯云直播的实时音视频实战笔记
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- PHP垃圾回收机制的一些浅薄理解
相信只要入门学习过一点开发的同学都知道,不管任何编程语言,一个变量都会保存在内存中.其实,我们这些开发者就是在来回不停地操纵内存,相应地,我们如果一直增加新的变量,内存就会一直增加,如果没有一个好的机 ...
- use关键字在PHP中的几种用法
在学习了和使用了这么多年的PHP之后,您知道use这个关键字在PHP中都有哪些用法吗?今天我们就来看一下它的三种常见用法. 1. 用于命名空间的别名引用 // 命名空间 include 'namesp ...
- echsop设置伪静态
1.后台商店设置-基本设置-URL重写开启 2.修改httpd.conf文件 AllowOverride None 改为 AllowOverride AllLoadModule rewrite_mod ...
- redis代替mybatis做缓存
将redis作为缓存 <dependencies> <dependency> <groupId>org.springframework.boot</group ...
- lua文件修改为二进制文件
注意:lua编译跟luajit编译的二进制文件是不兼容,不能运行的 如果是使用luajit,请直接使用luajit直接编译二进制 第一种:luajit编译(以openresty为例,跟luac是相反的 ...
- CF19E-Fairy【树形结构,差分】
正题 题目链接:https://www.luogu.com.cn/problem/CF19E 题目大意 给出\(n\)个点\(m\)条边的一张无向图,求有多少条边去掉后可以使得图变成一张二分图. \( ...
- P3352-[ZJOI2016]线段树【dp】
正题 题目链接:https://www.luogu.com.cn/problem/P3352 题目大意 \(n\)个数字的一个序列,每次随机选择一个区间让这个区间所有数等于这个区间的最大值,重复\(q ...
- 51nod1675-序列变换【莫比乌斯反演】
正题 题目连接:http://www.51nod.com/Challenge/Problem.html#problemId=1675 题目大意 给出两个长度为\(n\)的序列\(a,b\),求有多少对 ...
- P4001-[ICPC-Beijing 2006]狼抓兔子【对偶图】
正题 题目链接:https://www.luogu.com.cn/problem/P4001 题目大意 给出一个类似于 的网格图,求起点到终点的最小割. 解题思路 最小割直接跑网络流,然后发现\(di ...