【uboot】mips架构uboot启动分析

协处理器

协处理器一词通常用来表示处理器的一个可选部件,负责处理指令集的某个扩展。
- CP1 是浮点协处理器,
- CP0 系统控制协处理器
- CP2 偶尔用来指定ISA扩展或者在几个SoC应用中提供专用的寄存器;
- CP3 被MIPS32/64浮点指令占用,很少用;

协处理器CP0

除了通常的运算功能,任何处理器都需要一些部件处理中断,配置选项和监控片上高速缓存(cache)和定时器功能。
CP0协处理器主要提供:
1)cpu的配置;
2)高速缓存控制;
3)异常/中断控制;
4)存储管理单元控制;
5)杂项,如定时器,事件计数器,奇偶校验,错误检测;
在汇编中:
li t0, 0x10000004
mtc0 t0, $12 #状态寄存器,CPU的特权等级,能使用的中断引脚等。
mtc0 zero, $13

\boot\uboot\board\atheros\common中的956x.S中
lowlevel_init: 在956x.S中定义,设置CPU,AHB,DDR,

uboot 作为bootloader的一种,用于引导操作系统顺利启动,本文记录基于mips架构SDK中uboot的编译过程和启动流程

编译过程

编译过程可以分为三部分:

1.源码编译

uboot编译的方式是将各个目录下的源码编译成.o,然后通过mips-linux-uclibc-ar 命令创建成静态库,
./lib_bootstrap/libbootstrap.a
./cpu/mips/libmips.a
./board/atheros/board955x/libboard955x.a
./lib_mips/libmips.a
./lib_generic/libgeneric.a
./common/libcommon.a
./drivers/libdrivers.a
./rtc/librtc.a
./net/libnet.a
./post/libpost.a
./post/cpu/libcpu.a

到最后通过连接脚本将这些静态库链接成u-boot,如下:
mips-linux-uclibc-ld -Bstatic -T /***/boot/u-boot/board/atheros/board955x/u-boot.lds -Ttext 0x80010000 $UNDEF_SYM cpu/mips/start.o /***/boot/u-boot/board/atheros/board955x/extra.o \
--start-group lib_generic/libgeneric.a common/libcommon.a board/atheros/board955x/libboard955x.a cpu/mips/libmips.a lib_mips/libmips.a drivers/libdrivers.a net/libnet.a rtc/librtc.a --end-group -L /***/toolchain/gcc-4.3.3/build_mips/staging_dir/usr/bin/../lib/gcc/mips-linux-uclibc/4.3.3 -lgcc \
-Map u-boot.map -o u-boot

注意 -Ttext 0x80010000,这里是将初始地址重定向为0x80010000,如果不设置这个重定向地址,则为0;为什么是这个地址,后面再说!

2. 添加libbootstrap.a

首先将u-boot拷贝成u-boot.bin
mips-linux-uclibc-objcopy –gap-fill=0xff -O binary u-boot u-boot.bin 各个section之间填充0xff
然后编译目录lib_bootstrap,并生成libbootstrap.a,如下:
/home/project/plc_platform/board/model_qca_qca95xx/sdk/board956x/boot/u-boot/board/atheros/board955x/u-boot-bootstrap.lds -Ttext 0x9f000000 $UNDEF_SYM cpu/mips/start_bootstrap.o \
--start-group lib_bootstrap/libbootstrap.a board/atheros/board955x/libboard955x.a cpu/mips/libmips.a --end-group -L /home/project/plc_platform/board/model_qca_qca95xx/toolchain/gcc-4.3.3/build_mips/staging_dir/usr/bin/../lib/gcc/mips-linux-uclibc/4.3.3 -lgcc \
-Map bootstrap.map -o bootstrap

然后copy:
mips-linux-uclibc-objcopy --gap-fill=0xff -O binary bootstrap bootstrap.bin
这个libbootstrap.a包含了lzma解压缩的api,还有汇编文件start_bootstrap.S,这个文件十分重要,后面的uboot执行流程有介绍。注意-Ttext 0x9f000000,这个表明这部分代码是在flash中运行的,0x9f000000是flash地址的基地址。

lzma压缩和制作镜像

执行的makefile:
u-boot.lzimg: $(obj)u-boot.bin System.map
@$(LZMA) e $(obj)u-boot.bin u-boot.bin.lzma
@./tools/mkimage -A mips -T firmware -C lzma \
-a 0x$(shell grep "T _start" $(TOPDIR)/System.map | awk '{ printf "%s", $$1 }') \ -e 0x$(shell grep "T _start" $(TOPDIR)/System.map | awk '{ printf "%s", $$1 }') \
-n 'u-boot image' -d $(obj)u-boot.bin.lzma $@

分为两个过程,一个是调用lzma压缩,一个调用mkimage制作镜像。
LZMA 4.57 Copyright (c) 1999-2007 Igor Pavlov 2007-12-06
Image Name: u-boot image
Created: Mon Mar 28 16:01:07 2016
Image Type: MIPS Linux Firmware (lzma compressed)
Data Size: 40037 Bytes = 39.10 kB = 0.04 MB
Load Address: 0x80010000
Entry Point: 0x80010000
cp -f /home/project/plc_platform/board/model_qca_qca95xx/build/../sdk/board956x/boot/u-boot/tuboot.bin

mkimage主要是给压缩后的镜像添加一个头,这个头的结构如下:

typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number*/
uint32_t ih_hcrc; /* Image Header CRC Checksum*/
uint32_t ih_time; /* Image Creation Timestamp*/
uint32_t ih_size; /* Image Data Size*/
uint32_t ih_load; /* DataLoad Address*/
uint32_t ih_ep; /* Entry Point Address*/
uint32_t ih_dcrc; /* Image Data CRC Checksum*/
uint8_t ih_os; /* Operating System*/
uint8_t ih_arch; /* CPU architecture*/
uint8_t ih_type; /* Image Type*/
uint8_t ih_comp; /* Compression Type*/
uint8_t ih_name[IH_NMLEN]; /* Image Name*/
} image_header_t;

扫描二维码关注公众号,回复: 1633435 查看本文章

其中 uint32_t ih_load; /* DataLoad Address*/
uint32_t ih_ep; /* Entry Point Address
是两个关键的地址,ih_load是解压uboot到的目的地址,ih_ep是程序的入口地址。
到此,uboot编译完成,最终的uboot.bin的结构如下:
++++++++++++++++++++++++++++++
|bootstrap.bin|image header|u-boot.lzimg |
++++++++++++++++++++++++++++++

上电初始化过程

汇编初始化

根据硬件特性程序从入口Entry(_start)开始执行,主要的操作在start_bootstrap.S中进行,主要的操作:
初始化时钟,DDR,cache、禁止time中断
CPU PLL CONFIG
SDRM或 DDR initialization
Initialize caches(bal mips_cache_reset),建立暂时栈空间
Initialize GOT pointer//为调用函数建立的符号表指针
进入第一个c函数bootstrap_board_init_f:
la t9, bootstrap_board_init_f
j t9

bootstrap_board_init_f

bootstrap_board_init_f先执行初始化函数指针数组init_sequence,然后开辟一个临时栈空间,在DDR的最高位置。然后计算临时栈的起始位置
+++++++++++++++++++++++++++++++++++++++++++++++++
| |16B|128K uboot参数|gb_t|bd_t|malloc 128K|uboot的BSS&TEXT| 4K |
+++++++++++++++++++++++++++++++++++++++++++++++++
初始化一个临时栈空间,然后调用bootstrap_relocate_code,最后要清cache,然后跳转(不是很明白)
` bal mips_cache_flush
nop

/* Jump to where we’ve relocated ourselves.*/
addi t0, a2, in_ram - _start_bootstrap
j t0`
最后进入bootstrap_board_init_r

bootstrap_board_init_r

bootstrap_relocate_code在start_bootstrap.S中实现,将uboot的代码重定向到临时栈空间栋运行,进入函数bootstrap_board_init_r,
bootstrap_board_init_r函数首先初始化128K的栈空间,然后将uboot的header取出来,检查magic number和crc32校验,通过后调用函数lzma_inflate解压uboot:
i = lzma_inflate ((unsigned char )data, len, (unsigned char)ntohl(hdr->ih_load), &destLen);
解压成功后,清除cache,跳入uboot的入口:fn = ntohl(hdr->ih_load),既是0x80010000地址:
80010000 T _start
80010030 T relocate_code
80010094 t in_ram
80010100 T ath_set_tuning_caps
800101a0 T do_go
800102c0 T print_image_hdr
800106c8 T do_bootd
80010718 T fake_image_header
800107f0 T do_bootm
800109c0 T flash_sect_erase
80010bc8 T do_flerase

_start函数在start.S中,,执行以下操作
清空cache
清空BSS段
正式进入C环境(la t9 board_init_r)

board_init_r

board_init_r 主要执行以下的操作:
将前面临时栈一些数据(gd、bd等)copy到RAM中预留的对应位置
设置系统模式(Init_System_Mode),这里可以设置CPU时钟
env_relocate
devices_init //i2c、LCD、keyboard ……
main_loop循环监听,无人为干预,启动系统(do_bootm),有人为干预初始化以太网其他相关操作。
main_loop中调用了parse_string_outer 通过执行命令bootm 0x9f010000 进入到函数do_bootm;

do_bootm

do_bootm:解压缩kernel,调用do_bootm_linux

do_bootm_linux

do_bootm_linux:对kernel进行crc校验,并和header中的crc字段进行比较,设置环境变量,然后调用theKernel 进入kernel。

重要的宏

CFG_PLL_720_600_200 cpu memory 和总线的频率,对着这组配置,有一系列的宏定义:
#define CPU_DDR_SYNC_MODE DDR_CTL_CONFIG_CPU_DDR_SYNC_SET(0)
\#define CPU_PLL_CONFIG_NINT_VAL CPU_PLL_CONFIG_NINT_SET(18)
\#define CPU_PLL_CONFIG_REF_DIV_VAL CPU_PLL_CONFIG_REFDIV_SET(1)
\#define CPU_PLL_CONFIG_RANGE_VAL CPU_PLL_CONFIG_RANGE_SET(1)
\#define CPU_PLL_CONFIG_OUT_DIV_VAL1 CPU_PLL_CONFIG_OUTDIV_SET(0)
\#define CPU_PLL_CONFIG_OUT_DIV_VAL2 CPU_PLL_CONFIG_OUTDIV_SET(0)
\#define CPU_PLL_DITHER_VAL CPU_PLL_DITHER_DITHER_EN_SET(0) | \
CPU_PLL_DITHER_NFRAC_MAX_SET(0x3f) | \
CPU_PLL_DITHER_NFRAC_MIN_SET(0) | \
CPU_PLL_DITHER_NFRAC_STEP_SET(1) | \
CPU_PLL_DITHER_UPDATE_COUNT_SET(0xf)

#define DDR_PLL_CONFIG_NINT_VAL DDR_PLL_CONFIG_NINT_SET(15)
#define DDR_PLL_CONFIG_REF_DIV_VAL DDR_PLL_CONFIG_REFDIV_SET(1)
#define DDR_PLL_CONFIG_RANGE_VAL DDR_PLL_CONFIG_RANGE_SET(1)
#define DDR_PLL_CONFIG_OUT_DIV_VAL1 DDR_PLL_CONFIG_OUTDIV_SET(0)
#define DDR_PLL_CONFIG_OUT_DIV_VAL2 DDR_PLL_CONFIG_OUTDIV_SET(0)
#define DDR_PLL_DITHER_VAL DDR_PLL_DITHER_DITHER_EN_SET(0) | \
DDR_PLL_DITHER_NFRAC_MAX_SET(0x3ff) | \
DDR_PLL_DITHER_NFRAC_MIN_SET(0) | \
DDR_PLL_DITHER_NFRAC_STEP_SET(1) | \
DDR_PLL_DITHER_UPDATE_COUNT_SET(0xf)

#define CPU_DDR_CLOCK_CONTROL_AHB_DIV_VAL CPU_DDR_CLOCK_CONTROL_AHB_POST_DIV_SET(2)
#define AHB_CLK_FROM_DDR CPU_DDR_CLOCK_CONTROL_AHBCLK_FROM_DDRPLL_SET(1)
#define CPU_AND_DDR_CLK_FROM_DDR CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_DDRPLL_SET(0)
#define CPU_AND_DDR_CLK_FROM_CPU CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_CPUPLL_SET(0)
#define CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV_SET(0)
#define CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV_SET(0)

问题分析

Setting 0x181162c0 to 0x60c02100
\## Booting image at 9f010000 ...
---- fileTag = 9f010000
text base = ffffffff
entry point = ffffffff
hdr->ih_load = 00000000
hdr->ih_ep = 00000000
Uncompressing Kernel Image at ffffffff ... Stream with EOS marker is not supportedLZMA ERROR 1 - must RESET board to recover

kernel的偏移位置错了,应该是:export KERNEL_OFFSET=0x020000

尝试更换新旧平台的squashfs文件系统,发现需要找lib下的zlib驱动,又尝试整个kernel更换,发现编译以太网驱动失败,头文件找不到。
跟踪出错打印的函数调用栈,发现在unlzma出错,研究make_flash源码:
[ 0.776000] Call Trace:
[ 0.776000] [<800f02c8>] unlzma+0xfb4/0x118c

终于知道问题所在,新平台的文件打包工具使用的压缩方式是gzip,而不是lzma,在文件buildFS_LZ中:
$SOURCE/util/mksquashfs4.0 $INSTALL_ROOT_FOR_BOARD $IMAGEPATH/$BOARD_TYPE-squashfs -noappend -always-use-fragments -all-root -b 1048576
关键是Z:\source\util目录下的mksquashfs4是不支持lzma的,更换为旧的mksquashfs4.0就可以了。

猜你喜欢

转载自blog.csdn.net/vickytong1018/article/details/70449025