基于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 [email protected]

也就是说,在编译的时候,就决定了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]

bootdelay=4[xxx9]

baudrate=115200

ethaddr=0x00:0xaa:0xbb:0xcc:0xdd:0xee

ipaddr=192.168.1.2[xxx10]

serverip=192.168.1.10[xxx11]

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

Load Address: 80002000[xxx15]

Entry Point:  8019bd60[xxx16]

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)  :

² 获得内核镜像的启动地址:

theKernel =

(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的报文段会从此地址开始

[xxx3]

-a 0xffffffff80010000 \

-e 0xffffffff80010000 \

[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]创建内核线程

时间: 2024-12-28 15:52:43

基于AR9331(MIPS架构)分析系统启动过程(uboot)的相关文章

为什么要有uboot?带你全面分析嵌入式linux系统启动过程中uboot的作用

1.为什么要有uboot 1.1.计算机系统的主要部件 (1)计算机系统就是以CPU为核心来运行的系统.典型的计算机系统有:PC机(台式机+笔记本).嵌入式设备(手机.平板电脑.游戏机).单片机(家用电器像电饭锅.空调) (2)计算机系统的组成部件非常多,不同的计算机系统组成部件也不同.但是所有的计算机系统运行时需要的主要核心部件都是3个东西: CPU + 外部存储器(Flash/硬盘) + 内部存储器(DDR SDRAM/SDRAM/SRAM) 1.2.PC机的启动过程 (1)部署:典型的PC

魏昊卿——《Linux内核分析》第三周作业:Linux系统启动过程

魏昊卿——<Linux内核分析>第三周作业:Linux系统启动过程 一.实验部分 实验指导 使用实验楼的虚拟机打开shell 1 cd LinuxKernel/ 2 qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img 内核启动完成后进入menu程序(<软件工程C编码实践篇>的课程项目),支持三个命令help.version和quit,您也可以添加更多的命令,对选修过<软件工程C编码实践篇>

基于C/S架构的3D对战网络游戏C++框架 _03客户端详细设计与OpenGL、Qt基础

本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): 1.实现基本通信框架,包括对游戏的需求分析.设计及开发环境和通信框架的搭建: 2.实现网络底层操作,包括创建线程池.序列化网络包等: 3.实战演练,实现类似于CS反恐精英的3D对战网络游戏: 技术要点:C++面向对象思想.网络编程.Qt界面开发.Qt控件知识.Boost智能指针.STL算法.STL.

分布式MySQL数据库TDSQL架构分析

摘要:腾讯计费平台部为了解决基于内存的NoSQL解决方式HOLD平台在应对多种业务接入时的不足.结合团队在MySQL领域多年应用和优化经验,终于在MySQL存储引擎基础上,打造一套分布式SQL系统TDSQL.本文是对该系统架构分析. 腾讯计费平台部托管着公司90%以上的虚拟账户.如QB.Q点.包月服务.游戏的二级账户等,为了保证能顺畅支撑公司各大业务的实时在线交易.而且在各种灾难场景下数据是一致而且可用的,对系统的可用性.一致性切换要求很高,因此计费团队历来都很重视高一致性存储系统的建设. 到眼

win10系统调用架构分析

1.  操作系统模型 大多数操作系统中,都会把应用程序和内核代码分离运行在不同的模式下.内核模式访问系统数据和硬件,应用程序运行在没有特权的模式下(用户模式),只能使用有限的API,且不能直接访问硬件.当用户模式调用系统服务时,CPU执行一个特殊的指令以切换到内核模式(Ring0),当系统服务调用完成时,操作系统切换回用户模式(Ring3). Windows与大多数UNIX系统类似,驱动程序代码共享内核模式的内存空间,意味着任何系统组件或驱动程序都可能访问其他系统组件的数据.但是,Windows

基于消息系统架构设计

近期在弄一个业务系统,这个业务系统原本是有一个架构的,可是在后期扩展时发现问题多多.关键扩展非常不方便,并且由于业务系统安全规格较高.数据网络连接须要通过多个闸口传递才可,并且业务系统可能须要多地系统联合组网.共享业务数据,可是各地系统又必须相互独立. 用户希望改动架构,让系统可扩展性添加,同一时候要满足系统相互独立方便升级和兴许开发. 依照用户的要求我考虑使用一个基于消息传递的架构设计来满足需求. 所谓基于消息,就是通过消息中转server,中转全部系统间连接数据,同一时候管理数据路由,由消息

人人网张铁安:Feed系统架构分析(转)

原文:http://www.csdn.net/article/2010-07-26/277273 继成功举办首期TUP活动后,日前在北京丽亭华苑酒店鸿运二厅,由CSDN和<程序员> 杂志联合策划组织的TUP第二次活动如期而至,本次活动以Web 2.0技术为主题,聚焦当下火热的社交网.微博架构与实时搜索领域.就相关领域及产品研发背后的技术.产品设计及用户体验话题为与会者提供全开放式的交流 平台.即使是付费沙龙,参会报名人数仍在不断上升,本次活动有超过300人来到现场. 人人网技术经理张铁安 以下

基于TI Davinci架构的多核/双核开发高速扫盲(以OMAP L138为例),dm8168多核开发參考以及达芬奇系列资料user guide整理

基于TI Davinci架构的双核嵌入式应用处理器OMAPL138开发入门 原文转自http://blog.csdn.net/wangpengqi/article/details/8115614 感谢wangpengqi的共享. 一.简单介绍 TI的达芬奇架构嵌入式应用处理器使用DSP与ARM结合的非对称多核结构,当然如今也有管脚全兼容的单核.本文要介绍的就是当中的一款低功耗处理器OMAP L138. OMAP L138包含一个主频300M的ARM9处理器内核和一个300M的C6748DSP内核

二、OpenStack入门 之 架构分析

OpenStack入门 之 架构分析 写在前面 学习目标: 了解 OpenStack 各组件的逻辑关系: 了解 OpenStack 的各组件的通信和部署关系: 了解 OpenStack 的工作流程: 接下来我会掌握: OpenStack 组件间的逻辑关系: OpenStack 的API: OpenStack 组件间的通信关系: OpenStack 中几种不同的存储: OpenStack 工作流程: OpenStack 的部署架构: OpenStack 各组件之间的关系有:逻辑关系,通信关系,部署