uboot 源码下载、编译
1. 源码地址https://ftp.denx.de/pub/u-boot/2. 找到想要的版本此处我下载的是 u-boot-2012.10.tar.bz2。3. 将源码拿到 linux 环境下解压缩注意,使用 linux 虚拟机的话,不能在 linux-window 共享目录下编译,会报错。必须拷贝到纯 linux 环境的目录下解压缩。cp /mnt/hgfs/linux_win_shared/
1. 源码地址
https://ftp.denx.de/pub/u-boot/
2. 找到想要的版本
此处我下载的是 u-boot-2012.10.tar.bz2。
3. 将源码拿到 linux 环境下解压缩
注意,使用 linux 虚拟机的话,不能在 linux-window 共享目录下编译,会报错。
必须拷贝到纯 linux 环境的目录下解压缩。
cp /mnt/hgfs/linux_win_shared/u-boot-2012.10.tar.bz2 . # 将 uboot 源码从共享目录拷贝到 Linux 目录
tar -xvf u-boot-2012.10.tar.bz2 # 解压缩
root@backvm-virtual-machine:u-boot-2012.10# pwd
/home/backvm/work0/u-boot-2012.10
root@backvm-virtual-machine:u-boot-2012.10# ls -lhtr
总用量 2.2M
drwxrwxr-x 2 root root 4.0K 10月 15 2012 spl
-rw-rw-r-- 1 root root 74 10月 15 2012 snapshot.commit
-rw-rw-r-- 1 root root 2.5K 10月 15 2012 rules.mk
-rw-rw-r-- 1 root root 176K 10月 15 2012 README
drwxrwxr-x 3 root root 4.0K 10月 15 2012 nand_spl
-rwxrwxr-x 1 root root 4.5K 10月 15 2012 mkconfig
-rw-rw-r-- 1 root root 28K 10月 15 2012 Makefile
-rwxrwxr-x 1 root root 21K 10月 15 2012 MAKEALL
-rw-rw-r-- 1 root root 25K 10月 15 2012 MAINTAINERS
drwxrwxr-x 11 root root 4.0K 10月 15 2012 fs
drwxrwxr-x 4 root root 4.0K 10月 15 2012 examples
drwxrwxr-x 2 root root 4.0K 10月 15 2012 dts
drwxrwxr-x 28 root root 4.0K 10月 15 2012 drivers
drwxrwxr-x 6 root root 4.0K 10月 15 2012 doc
-rw-rw-r-- 1 root root 12K 10月 15 2012 CREDITS
-rw-rw-r-- 1 root root 17K 10月 15 2012 COPYING
-rw-rw-r-- 1 root root 11K 10月 15 2012 config.mk
-rw-rw-r-- 1 root root 113K 10月 15 2012 boards.cfg
drwxrwxr-x 290 root root 12K 10月 15 2012 board
drwxrwxr-x 16 root root 4.0K 10月 15 2012 arch
drwxrwxr-x 19 root root 12K 11月 11 23:58 include
drwxrwxr-x 12 root root 4.0K 11月 11 23:58 tools
drwxrwxr-x 2 root root 4.0K 11月 11 23:58 api
drwxrwxr-x 3 root root 12K 11月 11 23:58 common
......
4. 编译 uboot
root@backvm-virtual-machine:work0# cd u-boot-2012.10
root@backvm-virtual-machine:work0#
root@backvm-virtual-machine:u-boot-2012.10# make s5p_goni_config
Configuring for s5p_goni board...
root@backvm-virtual-machine:u-boot-2012.10#
root@backvm-virtual-machine:u-boot-2012.10# make
Generating include/autoconf.mk
Generating include/autoconf.mk.dep
arm-linux-gcc -DDO_DEPS_ONLY \
-g -Os -fno-common -ffixed-r8 -msoft-float -D__KERNEL__ -DCONFIG_SYS_TEXT_BASE=0x34800000 -I/home/backvm/work0/u-boot-2012.10/include -fno-builtin -ffreestanding -nostdinc -isystem /home/backvm/work0/linux_ker/gcc-4.6.4/bin/../lib/gcc/arm-arm1176jzfssf-linux-gnueabi/4.6.4/include -pipe -DCONFIG_ARM -D__ARM__ -marm -mno-thumb-interwork -mabi=aapcs-linux -march=armv7-a -Wall -Wstrict-prototypes -fno-stack-protector -Wno-format-nonliteral -Wno-format-security -fstack-usage \
-o lib/asm-offsets.s lib/asm-offsets.c -c -S
......
root@backvm-virtual-machine:u-boot-2012.10# ls -lh u* # uboot 编译成功
-rwxr-xr-x 1 root root 847K 11月 11 23:58 u-boot
-rw-r--r-- 1 root root 182K 11月 11 23:58 u-boot.bin
-rw-r--r-- 1 root root 923 11月 11 23:58 u-boot.lds
-rw-r--r-- 1 root root 77K 11月 11 23:58 u-boot.map
-rw-r--r-- 1 root root 545K 11月 11 23:58 u-boot.srec
root@backvm-virtual-machine:u-boot-2012.10#
5. 理解 uboot 中的汇编指令
arm-linux-objdump -S
命令
arm-linux-objdump -S
命令,可以让我们查看汇编代码对应的指令,以及根据汇编指令翻译出 “直观的汇编程序”。
如上图,汇编代码 _start: b reset
所在的内存地址为 34800000
, 汇编代码 _start: b reset
所对应的汇编指令为 ea000014
,这是一个四个字节的汇编指令。
在后面,arm-linux-objdump -S
命令根据汇编指令 ea000014
,翻译出直观的汇编代码为:b 34800058 <reset>
。
即:_start: b reset
等价于 b 34800058 <reset>
。
指令:ldr pc, _undefined_instruction
接下来是第二条汇编程序:ldr pc, _undefined_instruction
,它的意思是,将 标号_undefined_instruction
地址处的内容(即位于下方的34800020
地址处的内容34800200
)放入 pc 指针。
此处有个问题:我们知道, 一条 ARM 指令的长度是 4 个字节,而标号_undefined_instruction
代表的内容34800200
也是 4 个字节;34800200
(4 字节)+ ldr(n 字节)+ pc (n 字节) > 4 字节,明显不对劲。为什么呢?
实际上,我们看到的汇编程序 ldr pc, _undefined_instruction
是一条伪指令,汇编器会把它翻译为 ldr pc, [pc, #20]
。即当前指令 ldr pc, _undefined_instruction
的内存地址为 34800004
,pc 指针指向该内存地址 34800004
; [pc, #20]
将 pc 地址加上 20
的值,即 0x34800004 + 20 = 0x34800018;ldr pc, [pc, #20]
将地址 34800018
放入 pc 指针。我们看到 地址为 34800018
的汇编程序是:ldr pc, _irq
,明显不是我们的标号_undefined_instruction
的地址。这又是为什么呢?
这就涉及到 ARM 架构的“流水线”的概念了。
一条汇编程序(汇编指令),需要经历三个步骤才能执行完成:取指令——译码——执行。
即:
1) pc 指向第一条指令,此时 CPU 从内存中取出 第一条指令(取指);接着 pc 指针向前偏移一条指令。
2) pc 指向第二条指令,此时 CPU 对上面取出的第一条指令进行解析(译码);接着 pc 指针向前偏移一条指令。
3) pc 指向第三条指令,此时 CPU 执行译码后的指令(执行);
所以, pc 的值,等于当前 CPU 执行的指令所在地址值 + 8(ARM 一条指令是 4 个字节,即 pc 的值领先 2 条 ARM 指令)。
即,
-
当前指令
ldr pc, _undefined_instruction
的内存地址为34800004
,pc 当前的值已经向前偏移了 2 条指令(8个字节),为0x34800004 + 8 = 0x3480000C
。 -
[pc, #20]
:将该内存地址加上20
的值,为0x3480000C+ 20 = 0x34800020
;即,标号<_undefined_instruction>
所在的内存地址。
ldr pc, [pc, #20]
:因此这条指令的作用为, 将标号<_undefined_instruction>
的内容34800200
,放入 pc 指针;因此下一条取指的汇编指令为如下图所示的异常处理程序:
指令 .balignl 16,0xdeadbeef
:
该指令的作用是,指导汇编器,该条指令 .balignl 16,0xdeadbeef
的下一条指令 _TEXT_BASE
的内存地址,需要 16 字节对齐。如果不能16字节对齐,则从 .balignl 16,0xdeadbeef
的上一条指令 _pad: .word 0x12345678
开始,不断填充内容: 0xdeadbeef
。直到指令 _TEXT_BASE
的内存地址是 16 字节对齐为止。
可以看到,指令 34800040 <_TEXT_BASE>:
的内存地址确实是 16 字节对齐了。
指令:_TEXT_BASE: .word CONFIG_SYS_TEXT_BASE
CONFIG_SYS_TEXT_BASE
是在配置文件中定义的变量,即,使用命令make s5p_goni_config
的配置文件。
这个变量地址,就是将 uboot 拷贝到 DDR 中的起始内存地址。
从下图可以看到,这个内存地址就是:0x34800000
。
中断地址:0x0badc0de
这里主要是用来说明堆栈地址开始的地方。
因为我们的程序刚开始运行,还没有做初始化,还不知道堆栈指针应该指向什么地方。
所以此处用特殊内容0x0badc0de
填充,以便后续找到该地方,修改原内容0x0badc0de
,填充其他特定的内容。
指令:bl save_boot_params
在 start.S
文件中,一开始就使用指令:_start: b reset
跳转到 reset 标号处;下面 bl save_boot_params
就是 reset 的内容。
汇编指令 b
与 bl
的区别:
1) b
是普通的跳转指令,不带 return
(回复)的跳转。相当于 C 语言的 goto
指令,跳转到指定标号处之后,就从标号处顺序往下执行。
2)bl
是带 return
(回复)的跳转。就相当于 C 语言中,在此处调用一个函数
,函数执行完后,又 return
(回到)到 函数
被调用的地方,继续往下执行。
在 start.S
文件中就是, bl
执行完 save_boot_params
后,又回到此处,继续执行下面的 mrs r0, cpsr
。
bl
的本质是,在跳转之前,会先记录指令 mrs r0, cpsr
的内存地址,将其存放到 lr
寄存器。在 save_boot_params
的最后,使用汇编指令 mov pc, lr
,将保存的 lr
的内存地址(即指令 mrs r0, cpsr
的内存地址)放入 pc 指针,于是程序的下一条指令将执行 mrs r0, cpsr
。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)