技术心得:基于AR9331(MIPS架构)分析系统启动过程(uboot)

简介: 技术心得:基于AR9331(MIPS架构)分析系统启动过程(uboot)

前提:


1.AR9331是基于MIPS 24K CPU的一款WIFI1X1芯片,其SDK采用uboot作为引导。AR9331中定义的基地址是:0x9f00,0000


2.MIPS24K芯片,将固定的起始地址,规定为0xBF00,0000(见 和有提到)


此地址属于MIPS的KSEG1的地址范围内(见其实际的物理地址是: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


此文件的作用:


2 连接脚本是用来描述输出文件的内存布局;源代码经过编译器编译后包含如下段:


n 正文段text:包含程序的指令代码;


n 数据段data:包含固定的数据,如常量和字符串;


n 未初始化数据段:包含未初始化的变量、数组等。


连接器的任务是将多个编译后的文件的text、data和bass等段连接在一起;而连接脚本文件就是告诉连接器从什么地址(运行时地址)开始放置这些段


2 此文件中,最要关注的是.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_bootcmd##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) :


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


theKernel =


(void ()(int, char , char , int)) ntohl (hdr->ih_ep);


2 【xxx18】 解析boot_args字段,得到:


linux_params_init (UNCACHED_SDRAM (gd->bd->bi_boot_params), commandline);


2 最后,直接运行内核镜像的启动地址:


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)


//代码参考:https://weibo.com/u/7930570539

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

相关文章
|
21天前
|
监控 安全 API
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
本文详细介绍了PaliGemma2模型的微调流程及其在目标检测任务中的应用。PaliGemma2通过整合SigLIP-So400m视觉编码器与Gemma 2系列语言模型,实现了多模态数据的高效处理。文章涵盖了开发环境构建、数据集预处理、模型初始化与配置、数据加载系统实现、模型微调、推理与评估系统以及性能分析与优化策略等内容。特别强调了计算资源优化、训练过程监控和自动化优化流程的重要性,为机器学习工程师和研究人员提供了系统化的技术方案。
142 77
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
|
15天前
|
机器学习/深度学习 算法 数据可视化
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
本文探讨了在量化交易中结合时序特征和静态特征的混合建模方法。通过整合堆叠稀疏降噪自编码器(SSDA)和基于LSTM的自编码器(LSTM-AE),构建了一个能够全面捕捉市场动态特性的交易系统。SSDA通过降噪技术提取股票数据的鲁棒表示,LSTM-AE则专注于捕捉市场的时序依赖关系。系统采用A2C算法进行强化学习,通过多维度的奖励计算机制,实现了在可接受的风险水平下最大化收益的目标。实验结果显示,该系统在不同波动特征的股票上表现出差异化的适应能力,特别是在存在明确市场趋势的情况下,决策准确性较高。
53 5
基于深度混合架构的智能量化交易系统研究: 融合SSDA与LSTM自编码器的特征提取与决策优化方法
|
26天前
|
机器学习/深度学习 人工智能 并行计算
【AI系统】Kernel 层架构
推理引擎的Kernel层负责执行底层数学运算,如矩阵乘法、卷积等,直接影响推理速度与效率。它与Runtime层紧密配合,通过算法优化、内存布局调整、汇编优化及调度优化等手段,实现高性能计算。Kernel层针对不同硬件(如CPU、GPU)进行特定优化,支持NEON、AVX、CUDA等技术,确保在多种平台上高效运行。
80 32
|
26天前
|
存储 机器学习/深度学习 人工智能
【AI系统】计算图优化架构
本文介绍了推理引擎转换中的图优化模块,涵盖算子融合、布局转换、算子替换及内存优化等技术,旨在提升模型推理效率。计算图优化技术通过减少计算冗余、提高计算效率和减少内存占用,显著改善模型在资源受限设备上的运行表现。文中详细探讨了离线优化模块面临的挑战及解决方案,包括结构冗余、精度冗余、算法冗余和读写冗余的处理方法。此外,文章还介绍了ONNX Runtime的图优化机制及其在实际应用中的实现,展示了如何通过图优化提高模型推理性能的具体示例。
55 4
【AI系统】计算图优化架构
|
11天前
|
机器学习/深度学习 存储 人工智能
基于AI的实时监控系统:技术架构与挑战分析
AI视频监控系统利用计算机视觉和深度学习技术,实现实时分析与智能识别,显著提升高风险场所如监狱的安全性。系统架构包括数据采集、预处理、行为分析、实时决策及数据存储层,涵盖高分辨率视频传输、图像增强、目标检测、异常行为识别等关键技术。面对算法优化、实时性和系统集成等挑战,通过数据增强、边缘计算和模块化设计等方法解决。未来,AI技术的进步将进一步提高监控系统的智能化水平和应对复杂安全挑战的能力。
|
16天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
51 3
|
14天前
|
前端开发 搜索推荐 安全
陪玩系统架构设计陪玩系统前后端开发,陪玩前端设计是如何让人眼前一亮的?
陪玩系统的架构设计、前后端开发及前端设计是构建吸引用户、功能完善的平台关键。架构需考虑用户需求、技术选型、安全性等,确保稳定性和扩展性。前端可选用React、Vue或Uniapp,后端用Spring Boot或Django,数据库结合MySQL和MongoDB。功能涵盖用户管理、陪玩者管理、订单处理、智能匹配与通讯。安全性方面采用SSL加密和定期漏洞扫描。前端设计注重美观、易用及个性化推荐,提升用户体验和平台粘性。
44 0
|
14天前
|
监控 Java 数据中心
微服务架构系统稳定性的神器-Hystrix
Hystrix是由Netflix开源的库,主要用于微服务架构中的熔断器模式,防止服务调用失败引发级联故障。它通过监控服务调用的成功和失败率,在失败率达到阈值时触发熔断,阻止后续调用,保护系统稳定。Hystrix具备熔断器、资源隔离、降级机制和实时监控等功能,提升系统的容错性和稳定性。然而,Hystrix也存在性能开销、配置复杂等局限,并已于2018年进入维护模式。
26 0

热门文章

最新文章