基于AR9331(MIPS架构)分析系统启动过程(uboot)
前提:
1.AR9331是基于MIPS 24K CPU的一款WIFI1X1芯片,其SDK采用uboot作为引导。AR9331中定义的基地址是:0x9f00,0000
2.MIPS24K芯片,将固定的起始地址,规定为0xBF00,0000(见http://blog.csdn.net/phunxm/article/details/9393021 和http://www.cnblogs.com/xmphoenix/archive/2011/11/02/2233397.html有提到)
此地址属于MIPS的KSEG1的地址范围内(见http://blog.csdn.net/phunxm/article/details/9393021),其实际的物理地址是:0x1F00,0000(=0xBF00,0000 & 0x1FFF,FFFF)
A.
uboot在编译时,会经历如下动作:
bootstrap: depend version $(SUBDIRS) $(OBJS_BOOTSTRAP) $(LIBS_BOOTSTRAP) $(LDSCRIPT_BOOTSTRAP)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS_BOOTSTRAP) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
$(LD) $(LDFLAGS_BOOTSTRAP[xxx1] ) $$UNDEF_SYM $(OBJS_BOOTSTRAP) \
--start-group $(LIBS_BOOTSTRAP) --end-group $(PLATFORM_LIBS) \
-Map bootstrap.map -o bootstrap
和
u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
$(LD) $(LDFLAGS)[xxx2] $$UNDEF_SYM $(OBJS) $(BOARD_EXTRA_OBJS) \
--start-group $(LIBS) --end-group $(PLATFORM_LIBS) \
-Map u-boot.map -o u-boot
以及
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 }') \
[xxx3] -n 'u-boot image' -d $(obj)u-boot.bin.lzma $@
也就是说,在编译的时候,就决定了tuboot需要在0x9f000000处被引导启动,也就是说,烧写tuboot时,需要烧到0x9f000000[xxx4] 处。
而0x9F00,0000属于KSEG0范围,其实际对应的物理地址也是0x1F00,0000[xxx5] (=0x9F00,0000&0x7FFF,FFFF)
B. Uboot编译连接脚本文件,在ap121上,就是/boot/u-boot/board/ar7240/ap121/u-boot.lds
此文件的作用:
² 连接脚本是用来描述输出文件的内存布局;源代码经过编译器编译后包含如下段:
n 正文段text:包含程序的指令代码;
n 数据段data:包含固定的数据,如常量和字符串;
n 未初始化数据段:包含未初始化的变量、数组等。
连接器的任务是将多个编译后的文件的text、data和bass等段连接在一起;而连接脚本文件就是告诉连接器从什么地址(运行时地址)开始放置这些段
² 此文件中,最要关注的是.text字段。一切从这里开始
C. 先运行bootstrap,然后再运行uboot
在\boot\u-boot\board\ar7240\ap121\u-boot-bootstrap.lds,有定义:ENTRY(_start_bootstrap)
在\boot\u-boot\board\ar7240\ap121\u-boot.lds,有定义:ENTRY(_start)
而在boot\u-boot\board\ar7240\ap121\config.mk,有定义:
# ROM version
ifeq ($(COMPRESSED_UBOOT),1)
TEXT_BASE = 0x80010000 #对应uboot的TEXT正文地址,见u-boot.map的_start
BOOTSTRAP_TEXT_BASE = 0x9f000000 #对应bootstrap的TEXT正文地址,见bootstrap.map的_start_bootstrap
[xxx6] else
TEXT_BASE = 0x9f000000
Endif
所以,先执行_start_bootstrap,再执行_start。那么,这两个在哪儿?
D. 在bootstrap.map中,可以看到:
.text 0x000000009f000000 0x3aa0
*(.text)
.text 0x000000009f000000 0x8b0 cpu/mips/start_bootstrap.o
0x000000009f000000 _start_bootstrap
Address of section .text set to 0x9f000000
在u-boot.map中,可以看到:
.text 0x0000000080010000 0x17da0
*(.text)
.text 0x0000000080010000 0x3350 cpu/mips/start.o
0x0000000080010030 relocate_code
0x0000000080010000 _start
Address of section .text set to 0x80010000
然后,在boot/u-boot/cpu/mips中,可以找到:start_bootstrap.S和start.S
这两个,就是真正执行_start_boostrap和_start的地方
在__start_bootstrap中,可以看到:bootstrap_board_init_f和bootstrap_board_init_r。最后,在bootstrap_board_init_r中,有:
addr = (char *)(BOOTSTRAP_CFG_MONITOR_BASE + ((ulong)&uboot_end_data_bootstrap - dest_addr));
memmove (&header, (char *)addr, sizeof(image_header_t));
以及:
data = addr + sizeof(image_header_t);/*越过uboot的头,定位到uboot的净荷开始*/
fn = ntohl(hdr->ih_load);/*定位位于hdr->ih_load位置的起止程序,并执行之。这个程序就是__start*/
(*fn)(gd->ram_size);
可见,bootstrap中会定位并剥掉uboot的image_header_t的头,这样就会调位到__start。
下面,分析_start
E. 在start.S中,可以看到:board_init_f和board_init_r(boot/u-boot/lib_mips/board.c)。这就是从汇编进入C的两个入口。先board_init_f,再board_init_r;
最终,在board_init_r中,调用无限循环:
for (;;) {
main_loop ();
}
F. main_loop(boot/u-boot/common/main.c)中,最终会调用:run_command (lastcommand, flag);
G. 在run_command(boot/u-boot/common/main.c)中,利用find_cmd找到合适的cmd_tbl_t *cmdtp对象,最后执行((cmdtp->cmd) (cmdtp, flag, argc, argv)
并且,在cmd_bootm.c中,有定义:
U_BOOT_CMD(
bootm, CFG_MAXARGS, 1, do_bootm,
"bootm - boot application image from memory\n",
"[addr [arg ...]]\n - boot application image stored in memory\n"
"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
"\t'arg' can be the address of an initrd image\n"
);
在boot/u-boot/include/command.h中,有定义:
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}
那么,最初的((cmdtp->cmd) (cmdtp, flag, argc, argv),就会执行到do_bootm
H. 在boot模式下,敲入printenv,可以看到uboot所用到的环境变量的值:
ar7240> printenv
bootargs=console=ttyS0,115200 root=31:02 rootfstype=squashfs init=/sbin/init mtdparts=ar7240-nor0:256k(u-boot),64k(u-boot-env),2752k(rootfs),896k(uImage),64k(NVRAM),64k(ART)[xxx7]
bootcmd=bootm 0x9f300000[xxx8]
baudrate=115200
ethaddr=0x00:0xaa:0xbb:0xcc:0xdd:0xee
stdin=serial
stdout=serial
stderr=serial
ethact=eth0
这些环境变量的定义,是在boot/u-boot/common/environment.c中赋值的;而具体的来源,则大部分在文件boot/u-boot/include/configs/ap121.h中定义;并且这些宏定义,是通过boot/u-boot/common/env_nowhere.c中的env_init引导的。
I. 在编译内核镜像时,有如下命令:
/home/xxx/140703_AR9331_Dev/u11_OnlyBasicAndWLAN_AP121-4MB/build/../boot/u-boot/tools/mkimage -A mips -O linux -T kernel -C gzip -a 0x80002000 -e 0x8019bd60 -n Linux Kernel Image -d /home/xxx/140703_AR9331_Dev/u11_OnlyBasicAndWLAN_AP121-4MB/build/../linux/kernels/mips-linux-2.6.31/arch/mips/boot/vmlinux.bin.gz /home/xxx/140703_AR9331_Dev/u11_OnlyBasicAndWLAN_AP121-4MB/build/../images/ap121-2.6.31/vmlinux.gz.uImage[xxx12]
J. Uboot启动内核,是调用cmd_bootm.c中的do_bootm函数,其传入的命令参数就是:
bootm 0x9f300000[xxx13]
然后,可以看到如下的启动信息:
## Booting image at 9f300000 ...[xxx14]
Image Name: Linux Kernel Image
Created: 2013-02-06 22:27:48 UTC
Image Type: MIPS Linux Kernel Image (lzma compressed)
Data Size: 771996 Bytes = 753.9 kB
Verifying Checksum at 0x9f300040 ...OK
Uncompressing Kernel Image ... OK
上述这些信息,都是do_bootm函数中,读取镜像文件头image_header_t信息后得出的
然后,利用gunzip ((void *)ntohl(hdr->ih_load), unc_len, (uchar *)data, &len) != 0),将压缩的镜像文件解压缩到hdr->ih_load[xxx17] 指向的地址。
最后,调用do_bootm_linux (cmdtp, flag, argc, argv,addr, len_ptr, verify); 开始内核启动过程
K. do_bootm_linux(boot/u-boot/lib_mips/mips_linux.c) :
² 获得内核镜像的启动地址:
(void (*)(int, char **, char **, int)) ntohl (hdr->ih_ep);
² [xxx18] 解析boot_args字段,得到:
linux_params_init (UNCACHED_SDRAM (gd->bd->bi_boot_params), commandline);
² 最后,直接运行内核镜像的启动地址:
flash_size_mbytes = gd->bd->bi_flashsize/(1024 * 1024);
theKernel (linux_argc, linux_argv, linux_env, flash_size_mbytes);[xxx19]
L. entry: 0x8019bf90地址上的程序,是什么呢?
看一下:linux/kernels/mips-linux-2.6.31/System.map,搜索8019bf9,会发现:
ffffffff8019bf90 T kernel_entry
哈哈,原来该地址上的程序是:kernel_entry
M. kernel_entry在arch/mips/kernel/head.S中定义;并且最终会跳转到start_kernel函数,从而进入C代码
N. 这里就调用了start_kernel(linux/kernels/mips-linux-2.6.31/init/main.c)
O. Start_kernel->rest_init->kernel_thread([xxx20]kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);->kernel_init->init_post->run_init_process("/sbin/init"); --> 进入busybox的init流程
[xxx1]## LDFLAGS_BOOTSTRAP 中,含有-Bstatic -T $(LDSCRIPT_BOOTSTRAP) -Ttext $(BOOTSTRAP_TEXT_BASE) $(PLATFORM_LDFLAGS)
## BOOTSTRAP_TEXT_BASE,在boot\u-boot\board\ar7240\ap121\config.mk中有定义,指明了BOOTSTRAP_TEXT_BASE = 0x9f000000,即bootstrap的报文段会从此地址开始。
## 那么,也就是要求:需要将tuboot放到0x9f000000处。这样tuboot启动时,才能找到这里的正确位置
[xxx2]## LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
## 其中的$(TEXT_BASE)在boot\u-boot\board\ar7240\ap121\config.mk中有定义,指明了TEXT_BASE = 0x80010000,即uboot的报文段会从此地址开始
[xxx4]0x9f000000位于KSEG0地址段,其距离KSEG0地址段上限(0x9fffffff)还有0x1000000,即16M的空间。也就是说,设置0x9f000000作为基地址,也就意味着AR9331可以支持最多16MB Flash ---我的猜测,不知道是否正确
[xxx5]和MIPS24K的固定起始地址是一样的。这就是为何要规定基地址是0x9F00,0000的缘故
[xxx6]这是u-boot和bootstrap在内存中的运行域
[xxx7]由ap121.h中的CONFIG_BOOTARGS定义
表示传递给内核的启动参数
[xxx8]由ap121.h中的CONFIG_BOOTCOMMAND定义
表示自动启动时执行的命令
这里的0x9f300000就是linux内核的TEXT_BASE地址;这也正是uboot下的cp.b命令烧写Linux内核的目的地址
[xxx9]执行自动启动的等候秒数
[xxx10]由ap121.h中的CONFIG_IPADDR定义,表示uboot模式下,单板的IP地址
[xxx11]由ap121.h中的CONFIG_SERVERIP定义,表示uboot升级时,所认可的TFTP Server的IP地址
[xxx12]参数说明:
-a ==> set load address to 'addr' (hex) -- 表示内核的运行地址
-e ==> set entry point to 'ep' (hex)。
是入口地址
[xxx13]这就是在使用uboot烧写内核文件时,给出的基地址
[xxx14]对应bootm的参数
[xxx15]对应编译时的-a参数
[xxx16]对应编译时的-e参数
[xxx17]就是mkimage –a选项指定的地址
[xxx18]在ap121上,这个值就是entry: 0x8019bf90
[xxx19]也就是直接运行位于
entry: 0x8019bf90地址上的程序
[xxx20]创建内核线程
基于AR9331(MIPS架构)分析系统启动过程(uboot)的更多相关文章
- Android系统启动过程-uBoot+Kernel+Android
摘要:本文是参考大量网上资源在结合自己查看源代码总结出来的,让自己同时也让大家加深对Android系统启动过程有一个更加深入的了解!再次强调,本文的大多数功劳应归功于那些原创者们,同时一些必要的参考链 ...
- MIPS架构上函数调用过程的堆栈和栈帧
转载于CSDN:http://blog.csdn.net/do2jiang/article/details/5404566 在计算机科学中,Call stack是指存放某个程序的正在运行的函数的信息的 ...
- 为什么要有uboot?带你全面分析嵌入式linux系统启动过程中uboot的作用
1.为什么要有uboot 1.1.计算机系统的主要部件 (1)计算机系统就是以CPU为核心来运行的系统.典型的计算机系统有:PC机(台式机+笔记本).嵌入式设备(手机.平板电脑.游戏机).单片机(家用 ...
- PLUTO平台是由美林数据技术股份有限公司下属西安交大美林数据挖掘研究中心自主研发的一款基于云计算技术架构的数据挖掘产品,产品设计严格遵循国际数据挖掘标准CRISP-DM(跨行业数据挖掘过程标准),具备完备的数据准备、模型构建、模型评估、模型管理、海量数据处理和高纬数据可视化分析能力。
http://www.meritdata.com.cn/article/90 PLUTO平台是由美林数据技术股份有限公司下属西安交大美林数据挖掘研究中心自主研发的一款基于云计算技术架构的数据挖掘产品, ...
- MapReduce过程详解(基于hadoop2.x架构)
本文基于hadoop2.x架构详细描述了mapreduce的执行过程,包括partition,combiner,shuffle等组件以及yarn平台与mapreduce编程模型的关系. mapredu ...
- 基于React的PC网站前端架构分析
代码地址如下:http://www.demodashi.com/demo/12252.html 本文适合对象 有过一定开发经验的初级前端工程师: 有过完整项目的开发经验,不论大小: 对node有所了解 ...
- 国内经典BI系统架构分析
谈起商业智能BI,也许大家并不陌生,但你是否了解国内的各类BI系统架构? 自国内商业智能发展以来,就系统结构方面已经历了多次优化性的变革.目前国内商业智能BI系统的经典架构的模式包括数据层.业务层和应 ...
- Flickr 网站架构分析
Flickr 网站架构分析 Flickr.com 是网上最受欢迎的照片共享网站之一,还记得那位给Windows Vista拍摄壁纸的Hamad Darwish吗?他就是将照片上传到Flickr,后而被 ...
- b2c项目基础架构分析(二)前端框架 以及补漏的第一篇名词解释
继续上篇,上篇里忘记了也很重要的前端部分,今天的网站基本上是以一个启示页,然后少量的整页切换,大量的浏览器后台调用web服务局部.动态更新页面显示状态这种方式在运作的,从若干年前简单的ajax流行起来 ...
随机推荐
- 安装CentOS 6停在selinux-policy-targeted卡住的问题解决
在刚开始安装时,设置swap分区.设置swap分区.设置swap分区 参考: http://tieba.baidu.com/p/3817971339 http://blog.csdn.net/zhan ...
- UI控件---UIWebView
UIWebView是内置浏览器控件,可以用来浏览网页,文档等,今天就试着做一个简易的浏览器! 定义url的初始化方法和返回,前进,刷新三个方法,实现UIWebViewDelegate协议 @inter ...
- Android 中 Environment.getExternalStorageDirectory()无效
我们在处理缓存的时候,并不是每次都会在应用私有存储空间那里保存,很多时候是需要用到ExternalStorage.我们平时一般都是用Environment.getExternalStorageDire ...
- dd-wrt端口映射不出去的解决办法
本人有一个巴法络的WZR-HP-G450H系统自带的固件不好用,但是随机却带了一个官方定制的DD-WRT,于是刷了去,但是今天在做一个FTP的时候突然无论怎么样映射或是做DMZ都不会出去,终于找到解决 ...
- 最短路径——Floyd,Dijkstra(王道)
题目描述: 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线 ...
- <LeetCode OJ> 101. Symmetric Tree
101. Symmetric Tree My Submissions Question Total Accepted: 90196 Total Submissions: 273390 Difficul ...
- git学习——远程仓库操作
查看当前的远程库——git remote 列出了仅仅是远程库的简单名字 可以加上-v 现实对应的克隆地址 添加远程仓库——git remote add [shortname] [url] git re ...
- vlan 介绍
简介 在Linux中安装了802.1Q标签VLAN功能.VLAN是虚拟分配以太网的功能. 使用VLAN ID从物理上将一个以太网分割开.在VLAN环境下,具有相同VLAN ID 就可以相互通 ...
- unity3D打造skybox淡入淡出 - 移动开发
原地址:http://www.it2down.com/it-mobile/426479.htm 当前位置: IT异常查询网 » unity3D打造skybox淡入淡出 - 移动开发 www.it2do ...
- Django——如何使用Template以及如何向template传递变量
如何使用模板系统 在Python代码中使用Django模板的最基本方式如下: 可以用原始的模板代码字符串创建一个 Template 对象, Django同样支持用指定模板文件路径的方式来创建 Temp ...