mini-uboot 启动过程简单分析
2016-06-19 19:53
489 查看
单片机有最小系统,所谓最小系统,就是单片机能正常工作所需要的最少外设。对于Uboot来说,同样有个最小系统,因为Uboot最主要的功能就是引导内核。下面我们通过一个简单的Mini-Uboot来分析Uboot的启动加载过程。(只是分析过程,此Uboot具有引导内核功能)
注:这个uboot 只是具有基本的内核引导功能,只是作为前期简单的学习使用,入门而已,并不是正常的uboot 启动流程
具体uboot (u-boot-2013.01)启动过程移步Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析
下面是mini-uboot 的根目录树状图:
我们拿到一个工程,想了解它的功能,最方便的就是读它的makefile。
一、Makefile
[cpp] view
plain copy
sinclude include/config.mk
#ARCH=arm
#CPU=arm920t
#VENDOR=samsung
#SOC=s3c2410
#BOARD=smdk2410
SRC_TREE:=$(shell pwd)
MKCONFIG=$(SRC_TREE)/mkconfig
INCLUDE_PATH=include
DRIVER_PATH=driver
LIB_DIR=lib
CFLAG=-mabi=apcs-gnu -fno-builtin -fno-builtin-function -g -O0 -c -I$(INCLUDE_PATH) -I$(DRIVER_PATH) -o
LDFLAG=-Tcpu/arm/arm_cortexa8/map.lds -o
OBJS= cpu/$(ARCH)/$(CPU)/start.o
OBJS+=lib_arm/board.o
OBJS+=board/$(VENDOR)/$(BOARD)/lowlevel_init.o
OBJS+=board/$(VENDOR)/$(BOARD)/mem_setup.o
OBJS+=board/$(VENDOR)/$(BOARD)/nand.o
OBJS+=driver/uart.o
OBJS+=lib/string.o
OBJS+=common/do_go.o
OBJS+=common/main.o
ifeq ($(ARCH), arm)
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi-
endif
PROJ_NAME=mini_uboot
all: $(OBJS)
$(CROSS_COMPILE)ld $(OBJS) $(LDFLAG) $(PROJ_NAME).elf
$(CROSS_COMPILE)objcopy -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
$(CROSS_COMPILE)objdump -D $(PROJ_NAME).elf > $(PROJ_NAME).dis
cp *.bin /tftpboot
%.o: %.S
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
%.o: %.s
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
%.o: %.c
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
fsc100_config: # ARCH CPU VENDOR BOARD SOC
$(MKCONFIG) $(@:_config=) arm arm_cortexa8 samsung fsc100 s5pc100
#mkconfig fsc100 arm arm_cortexa8 samsung fsc100 s5pc100
smdk2410_config: # ARCH CPU VENDOR BOARD SOC
$(MKCONFIG) $(@:_config=) arm arm920t samsung smdk2410 s3c2410
clean:
@rm -rf $(OBJS) *.bin *.elf config.mk
这里以2440为例,咱们来分析:
[cpp] view
plain copy
#ARCH=arm
#CPU=arm920t
#VENDOR=samsung
#SOC=s3c2410
#BOARD=smdk2410
架构为arm,CPU为arm920t,生产商 samsung,片上系统sc2410,板子为smdk2410。
[cpp] view
plain copy
OBJS= cpu/$(ARCH)/$(CPU)/start.o
OBJS+=lib_arm/board.o
OBJS+=board/$(VENDOR)/$(BOARD)/lowlevel_init.o
OBJS+=board/$(VENDOR)/$(BOARD)/mem_setup.o
OBJS+=board/$(VENDOR)/$(BOARD)/nand.o
OBJS+=driver/uart.o
OBJS+=lib/string.o
OBJS+=common/do_go.o
OBJS+=common/main.o
OBJS为依赖文件,生成的.o文件。
[cpp] view
plain copy
ifeq ($(ARCH), arm)
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi-
endif
根据相应的架构,制作相应的交叉编译工具。
[cpp] view
plain copy
all: $(OBJS)
$(CROSS_COMPILE)ld $(OBJS) $(LDFLAG) $(PROJ_NAME).elf
$(CROSS_COMPILE)objcopy -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
$(CROSS_COMPILE)objdump -D $(PROJ_NAME).elf > $(PROJ_NAME).dis
第一步:连接 ;第二步:格式转换;第三步:反汇编 " >" 为重定向的意思;
[cpp] view
plain copy
%.o: %.S
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
%.o: %.s
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
%.o: %.c
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
将所有的.S 文件、.s文件、.c文件编译成.o文件。
注意:.S文件可以在编译过程接受参数,.s文件不可以。
二、链接文件
[cpp] view
plain copy
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start) //指定入口地址
SECTIONS //段信息
{
/* . */
. = 0x22000000; //elf文件的入口地址
. = ALIGN(4); //指定四字节对齐
.text : //代码段
{
cpu/arm/arm_cortexa8/start.o(.text) //确保执行的第一段代码是start.o
*(.text) //所有代码段融合在一起
}
. = ALIGN(4);
.rodata : //只读数据段
{ *(.rodata) } //所有数据段
. = ALIGN(4);
.data : //数据段
{ *(.data) }
. = ALIGN(4);
_start_bss = .; //bss段开始地址
.bss :
{ *(.bss) }
_end_bss = .; //bss段结束地址,两者可确定bss段大小
}
三、start.s文件(Uboot执行的第一个文件)
[cpp] view
plain copy
@ 汇编中的宏
.equ USER_MODE, 0x10 @define USER_MODE 0x10
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13
.equ MODE_MASK, 0x1f
.section .text
.global _start
@ 不支持异常处理的,这里只写了复位异常处理
_start:
vector:
b reset_handler
nop @undef ......
nop
nop
nop
nop
nop
nop
reset_handler:
@step 1: svc close irq fiq //第一步:将运行模式改成SVC模式
mrs r0, cpsr //修改cpsr模式位
bic r0, r0, #0x1f
orr r0, r0, #0xc0 @IRQ FIQ //关闭IRQ FIQ
msr cpsr_c, r0
@step 2: cache 关闭I CACHE D CACHE //第二步:关闭cache,直接运行,不需缓存
mrc p15, 0, r0, c12, c0, 0
bic r0, #0x1000
bic r0, #0x2
mcr p15, 0, r0, c12, c0, 0
@step 3: //第三步:调用电路板级初始化程序, system clock , dram, watchdog
@bl low_level_init //初始化时钟、dram、关闭看门狗
@step 4: sp-> 0x30000000 //第四步:设置栈指针,使其指向一个地址即可
ldr sp, =0x2e000000
@step 5: mini_uboot.bin > 16KB bin < 16KB
@step 5 代码自搬移
@copy_miniuboot_rto_sdram 如果你的代码大于了16KB代码需要实现自我搬移
@step 6: //第六步:清除BSS段,BSS段大小由链接文件里确定
@STEP 6.1 , 清除 BSS段
@
clear_bss:
ldr r0, =_start_bss @| BSS 起始地址
ldr r1, =_end_bss @| BSS 终止地址
mov r2, #0
bss_loop:
cmp r0, r1
strne r2, [r0], #4
bne bss_loop
@step 7, 进入C //跳转到C程序入口
b start_armboot
stop:
b stop
.end
注:这个uboot 只是具有基本的内核引导功能,只是作为前期简单的学习使用,入门而已,并不是正常的uboot 启动流程
具体uboot (u-boot-2013.01)启动过程移步Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析
下面是mini-uboot 的根目录树状图:
我们拿到一个工程,想了解它的功能,最方便的就是读它的makefile。
一、Makefile
[cpp] view
plain copy
sinclude include/config.mk
#ARCH=arm
#CPU=arm920t
#VENDOR=samsung
#SOC=s3c2410
#BOARD=smdk2410
SRC_TREE:=$(shell pwd)
MKCONFIG=$(SRC_TREE)/mkconfig
INCLUDE_PATH=include
DRIVER_PATH=driver
LIB_DIR=lib
CFLAG=-mabi=apcs-gnu -fno-builtin -fno-builtin-function -g -O0 -c -I$(INCLUDE_PATH) -I$(DRIVER_PATH) -o
LDFLAG=-Tcpu/arm/arm_cortexa8/map.lds -o
OBJS= cpu/$(ARCH)/$(CPU)/start.o
OBJS+=lib_arm/board.o
OBJS+=board/$(VENDOR)/$(BOARD)/lowlevel_init.o
OBJS+=board/$(VENDOR)/$(BOARD)/mem_setup.o
OBJS+=board/$(VENDOR)/$(BOARD)/nand.o
OBJS+=driver/uart.o
OBJS+=lib/string.o
OBJS+=common/do_go.o
OBJS+=common/main.o
ifeq ($(ARCH), arm)
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi-
endif
PROJ_NAME=mini_uboot
all: $(OBJS)
$(CROSS_COMPILE)ld $(OBJS) $(LDFLAG) $(PROJ_NAME).elf
$(CROSS_COMPILE)objcopy -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
$(CROSS_COMPILE)objdump -D $(PROJ_NAME).elf > $(PROJ_NAME).dis
cp *.bin /tftpboot
%.o: %.S
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
%.o: %.s
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
%.o: %.c
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
fsc100_config: # ARCH CPU VENDOR BOARD SOC
$(MKCONFIG) $(@:_config=) arm arm_cortexa8 samsung fsc100 s5pc100
#mkconfig fsc100 arm arm_cortexa8 samsung fsc100 s5pc100
smdk2410_config: # ARCH CPU VENDOR BOARD SOC
$(MKCONFIG) $(@:_config=) arm arm920t samsung smdk2410 s3c2410
clean:
@rm -rf $(OBJS) *.bin *.elf config.mk
这里以2440为例,咱们来分析:
[cpp] view
plain copy
#ARCH=arm
#CPU=arm920t
#VENDOR=samsung
#SOC=s3c2410
#BOARD=smdk2410
架构为arm,CPU为arm920t,生产商 samsung,片上系统sc2410,板子为smdk2410。
[cpp] view
plain copy
OBJS= cpu/$(ARCH)/$(CPU)/start.o
OBJS+=lib_arm/board.o
OBJS+=board/$(VENDOR)/$(BOARD)/lowlevel_init.o
OBJS+=board/$(VENDOR)/$(BOARD)/mem_setup.o
OBJS+=board/$(VENDOR)/$(BOARD)/nand.o
OBJS+=driver/uart.o
OBJS+=lib/string.o
OBJS+=common/do_go.o
OBJS+=common/main.o
OBJS为依赖文件,生成的.o文件。
[cpp] view
plain copy
ifeq ($(ARCH), arm)
CROSS_COMPILE=arm-cortex_a8-linux-gnueabi-
endif
根据相应的架构,制作相应的交叉编译工具。
[cpp] view
plain copy
all: $(OBJS)
$(CROSS_COMPILE)ld $(OBJS) $(LDFLAG) $(PROJ_NAME).elf
$(CROSS_COMPILE)objcopy -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin
$(CROSS_COMPILE)objdump -D $(PROJ_NAME).elf > $(PROJ_NAME).dis
第一步:连接 ;第二步:格式转换;第三步:反汇编 " >" 为重定向的意思;
[cpp] view
plain copy
%.o: %.S
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
%.o: %.s
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
%.o: %.c
$(CROSS_COMPILE)gcc $(CFLAG) $@ $<
将所有的.S 文件、.s文件、.c文件编译成.o文件。
注意:.S文件可以在编译过程接受参数,.s文件不可以。
二、链接文件
[cpp] view
plain copy
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start) //指定入口地址
SECTIONS //段信息
{
/* . */
. = 0x22000000; //elf文件的入口地址
. = ALIGN(4); //指定四字节对齐
.text : //代码段
{
cpu/arm/arm_cortexa8/start.o(.text) //确保执行的第一段代码是start.o
*(.text) //所有代码段融合在一起
}
. = ALIGN(4);
.rodata : //只读数据段
{ *(.rodata) } //所有数据段
. = ALIGN(4);
.data : //数据段
{ *(.data) }
. = ALIGN(4);
_start_bss = .; //bss段开始地址
.bss :
{ *(.bss) }
_end_bss = .; //bss段结束地址,两者可确定bss段大小
}
三、start.s文件(Uboot执行的第一个文件)
[cpp] view
plain copy
@ 汇编中的宏
.equ USER_MODE, 0x10 @define USER_MODE 0x10
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13
.equ MODE_MASK, 0x1f
.section .text
.global _start
@ 不支持异常处理的,这里只写了复位异常处理
_start:
vector:
b reset_handler
nop @undef ......
nop
nop
nop
nop
nop
nop
reset_handler:
@step 1: svc close irq fiq //第一步:将运行模式改成SVC模式
mrs r0, cpsr //修改cpsr模式位
bic r0, r0, #0x1f
orr r0, r0, #0xc0 @IRQ FIQ //关闭IRQ FIQ
msr cpsr_c, r0
@step 2: cache 关闭I CACHE D CACHE //第二步:关闭cache,直接运行,不需缓存
mrc p15, 0, r0, c12, c0, 0
bic r0, #0x1000
bic r0, #0x2
mcr p15, 0, r0, c12, c0, 0
@step 3: //第三步:调用电路板级初始化程序, system clock , dram, watchdog
@bl low_level_init //初始化时钟、dram、关闭看门狗
@step 4: sp-> 0x30000000 //第四步:设置栈指针,使其指向一个地址即可
ldr sp, =0x2e000000
@step 5: mini_uboot.bin > 16KB bin < 16KB
@step 5 代码自搬移
@copy_miniuboot_rto_sdram 如果你的代码大于了16KB代码需要实现自我搬移
@step 6: //第六步:清除BSS段,BSS段大小由链接文件里确定
@STEP 6.1 , 清除 BSS段
@
clear_bss:
ldr r0, =_start_bss @| BSS 起始地址
ldr r1, =_end_bss @| BSS 终止地址
mov r2, #0
bss_loop:
cmp r0, r1
strne r2, [r0], #4
bne bss_loop
@step 7, 进入C //跳转到C程序入口
b start_armboot
stop:
b stop
.end
相关文章推荐
- Android图片印刻,阳刻,素描图效果处理
- leetcode 11. Container With Most Water
- dos IP转载经典
- PostgreSQL将查询结果输出到新表
- 【57】android图片印刻,阳刻,素描图效果处理
- 【57】android图片印刻,阳刻,素描图效果处理
- Java NIO和IO的区别
- 一些对数学领域及数学研究的个人看法(转载自博士论坛wcboy)
- hdu 2089 不要62(数位DP)
- 【笔记】处理ssh 连接后一段时间就掉线 Connection closed by foreign host
- RMAN恢复 增加表空间后控制文件丢失
- Exynos4412 所用外存 —— eMMC
- 预览上传图片
- OAuth 2.0 —— Access Token
- 视图解析器InternalResourceViewResolver
- Spring mvc Interceptor 解决Session超时配置流程
- 极光推送——带(BroadCastReceive中消息跳转)
- Cocos2d-x之层间切换
- Exynos4412启动过程分析
- php总结