u-boot_mod 是具有web 浏览器的uboot,也就是传说中的不死uboot,这里的不死指的是不管怎么刷firmware

都可以方便更换firmware,而不是uboot本身就是不死的。

这里将其的代码分析一下。

代码的网址是:https://github.com/pepe2k/u-boot_mod

uboot的代码在openwrt上是最底层的,就像PC的BIOS。

整个uboot最开始的入口,是一段汇编语言(MIPS)代码

要证明这段代码是一开始执行的,首先要看链接器脚本(u-boot-bootstrap.lds):

链接器脚本

OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips")
OUTPUT_ARCH(mips)
ENTRY(_start_bootstrap)
SECTIONS
{
. = 0x00000000; . = ALIGN();
.text :
{
*(.text*)
} . = ALIGN();
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN();
.data : { *(.data*) } . = .;
_gp = ALIGN(); .got : {
__got_start_bootstrap = .;
*(.got)
__got_end_bootstrap = .;
} . = ALIGN();
.sdata : { *(.sdata*) } uboot_end_data_bootstrap = .;
num_got_entries = (__got_end_bootstrap - __got_start_bootstrap) >> ; . = ALIGN();
.sbss : { *(.sbss*) }
.bss : { *(.bss*) . = ALIGN(); }
uboot_end_bootstrap = .;
}

这里可以看到,程序入口是_start_bootstrap,程序的入口代码段(.text)地址是 0x00000000

那么,接下来分析最开始执行的代码(MIPS)

_start_bootstrap

start_bootstrap.s这个文件的入口处是_start_bootstrap

最终会调用到以下代码:

la t9, bootstrap_board_init_r

j t9

它的作用就是将bootstrap_board_init_r的地址load到t9寄存器,然后根据t9寄存器的内容跳转。

bootstrap_board_init_r

在bootstrap_board_init_r里面,会调用

fn = (void *)ntohl(hdr->ih_load);

(*fn)(gd->ram_size);

这里的hdr是根据image来设定的,这里不仔细分析了,得知其跳转的地址是start.s的_start
函数

_start

最终会调用到以下代码:

la t9, board_init_r

j t9

它的作用就是将board_init_r的地址load到t9寄存器,然后根据t9寄存器的内容跳转。

board_init_r

从这里开始,进入c语言的地盘了,下面逐个分析一下它们的作用。

从debug消息来看,这里已经开始在RAM上跑了。一开始是从硬件的0地址开始跑的,一开始的汇编中一般有将代码copy到RAM的过程(参考http://www.linuxidc.com/Linux/2012-08/68707.htm)。

printf("Now running in RAM - U-Boot at: %08lX\n", dest_addr);

接下来重新定位CMD table,

因为已经得到了 gd->reloc_off,那么将CMD table往后移动 gd->reloc_off。

    /*
* We have to relocate the command table manually
*/
for(cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++){
ulong addr; addr = (ulong)(cmdtp->cmd) + gd->reloc_off; cmdtp->cmd = (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr; addr = (ulong)(cmdtp->name) + gd->reloc_off;
cmdtp->name = (char *)addr; if(cmdtp->usage){
addr = (ulong)(cmdtp->usage) + gd->reloc_off;
cmdtp->usage = (char *)addr;
}
#ifdef CFG_LONGHELP
if(cmdtp->help){
addr = (ulong)(cmdtp->help) + gd->reloc_off;
cmdtp->help = (char *)addr;
}
#endif
}

那么什么是CMD
table呢?这里举个例子:

Cmd_boot.c (common):U_BOOT_CMD(go, CFG_MAXARGS, , do_go, "start application at address 'addr'\n",

Cmd_boot.c (common):U_BOOT_CMD(reset, , , do_reset, "perform RESET of the CPU\n", NULL);

Cmd_bootm.c (common):U_BOOT_CMD(bootm, , , do_bootm, "boot application image from memory\n", "[addr]\n"

Cmd_bootm.c (common):U_BOOT_CMD(boot, , , do_bootd, "boot default, i.e., run 'bootcmd'\n", NULL);

Cmd_bootm.c (common):U_BOOT_CMD(bootd, , , do_bootd, "boot default, i.e., run 'bootcmd'\n", NULL);

从 U_BOOT_CMD这个宏来看,已经将CMD
table的每一个entry和地址绑定了。

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}

其中开始和结束的范围就是
__u_boot_cmd_start 和
__u_boot_cmd_end

从链接脚本可以看到:

__u_boot_cmd_start = .;

.u_boot_cmd : { *(.u_boot_cmd) }

__u_boot_cmd_end = .;

除了CMD table 调整之外,这里对基本的硬件做了初始化:

/* 从硬件读取mac地址 */

memcpy(buffer, (void *)(CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_MAC_ADDRESS), );

/*get CPU/RAM/AHB clocks */

ar7240_sys_frequency(&cpu_freq, &ddr_freq, &ahb_freq);

/* configure available FLASH banks */

size = flash_init();

/* initialize malloc() area */

mem_malloc_init();

/* std in/out 初始化 */

devices_init();

console_init_r();

/* ethernet 初始化 */

eth_initialize(gd->bd);

当这些东西初始化完之后,执行main_loop

/* main_loop() can return to retry autoboot, if so just run it again. */
for(;;){
main_loop();
}

main_loop

在这里做了一些主要的分支工作,

uboot 里面集成了一个hush shell,可以将其看成一个精简的bash,可以处理用户的命令和一些脚本。

在这个main
loop里面,决定了从以下几种方式选择启动:

1.web
failsafe

2.U-Boot
console

3.U-Boot
netconsole

4.boot
command

用下图概括:

reset_button_status
指的是读取reset按键的状态,检测其是否按下。

httpd则实现了用web页面来更新firmware的操作。

关于网页更新firmware的http接口这个特色功能后面再分析,下面关注一下do_bootm后面的流程。

do_bootm

这个函数里面做了下面几个事情:

.print_image_hdr   //打印出firmware的头部,此时已经知道firmware所处的地址

.eth_halt //停止ethernet的协议栈,之前可能被开起来了,这里先关闭

.lzma_inflate //解压linux kernel 到内存

.do_bootm_linux //进入此函数,如果进入失败,就调用do_reset复位板子

do_bootm_linux

这里是uboot最后一个过程的函数了,它做了下面的事情:

1.linux_params_init/linux_env_set  //生成即将传入linux的一些参数

2.theKernel(linux_argc, linux_argv, linux_env, 0); //启动linux kernel

其中,theKernel的地址是这样来的:

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

这里的ih_ep指针的数据可以通过mkimage工具来指定,详见mkimage.c。

到这里为止。uboot的大体流程就分析好了,这个uboot本来就是定制过的,通过汉化、修改网页的

手段可以进一步进行定制,其中已经有很多做好的版本了,如果不是要深入研究uboot,建议拿现成的

来使用,毕竟openwrt主要关注的是firmware部分。

参考资料:http://www.cnblogs.com/lagujw/p/3996576.html

openwrt u-boot_mod 代码分析的更多相关文章

  1. Android代码分析工具lint学习

    1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...

  2. pmd静态代码分析

    在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...

  3. [Asp.net 5] DependencyInjection项目代码分析-目录

    微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...

  4. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)

    Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...

  5. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  6. STM32启动代码分析 IAR 比较好

    stm32启动代码分析 (2012-06-12 09:43:31) 转载▼     最近开始使用ST的stm32w108芯片(也是一款zigbee芯片).开始看他的启动代码看的晕晕呼呼呼的. 还好在c ...

  7. 常用 Java 静态代码分析工具的分析与比较

    常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...

  8. SonarQube-5.6.3 代码分析平台搭建使用

    python代码分析 官网主页: http://docs.sonarqube.org/display/PLUG/Python+Plugin Windows下安装使用: 快速使用: 1.下载jdk ht ...

  9. angular代码分析之异常日志设计

    angular代码分析之异常日志设计 错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最 ...

随机推荐

  1. SpringMVC 返回 html 视图页面,SpringMVC与Servlet,Servlet重定向与转发

    1. SpringMVC与Servlet的关系 SpringMVC框架是建立在Servlet之上的,提供各种功能,各种封装,各种方便的同时,它一点儿也没有限制Servlet,我们完全可以在Spring ...

  2. 最锋利的Visual Studio Web开发工具扩展:Web Essentials详解(转)

    Web Essentials是目前为止见过的最好用的VS扩展工具了,具体功能请待我一一道来. 首先,从Extension Manager里安装:最新版本是19号发布的2.5版 然后重启你的VS开发环境 ...

  3. 【VB超简单入门】二、知识准备

    在开始编程之前,需要先熟悉一下各种操作和术语,以后学习编程才能得心应手. 首先最重要的操作当然就是-电脑的开机关机啦~(开个玩笑哈哈),必须掌握软件的安装和卸载,还有能编写批处理程序对平时的使用也是很 ...

  4. codeforces C. Triangle

    C. Triangle time limit per test 1 second memory limit per test 256 megabytes input standard input ou ...

  5. redis unwatch discard

    UNWATCH UNWATCH 取消 WATCH 命令对所有 key 的监视. 如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行UNWATC ...

  6. Doctype文档类型、作用及触发方式

    Doctype文档类型 1)  该标签可声明三种 DTD 类型,分别表示严格版本.过渡版本以及基于框架的 HTML 文档. 2)  HTML 4.01 规定了三种文档类型:Strict.Transit ...

  7. jQuery时间轴插件:jQuery Timelinr

    前言 这是一款可用于展示历史和计划的时间轴插件,尤其比较适合一些网站展示发展历程.大事件等场景.该插件基于jQuery,可以滑动切换.水平和垂直滚动.支持键盘方向键.经过扩展后可以支持鼠标滚轮事件. ...

  8. Android组件---四大布局的属性详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 文章来源:http://www.cnblogs.com/smyhvae/p/4372222.html Android常见布局有下面几种: LinearL ...

  9. MySQL数据库学习笔记(九)----JDBC的ResultSet接口(查询操作)、PreparedStatement接口重构增删改查(含SQL注入的解释)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  10. 第23章 SEH结构化异常处理(2)_编译器对系统SEH机制的封装

    23.2 编译器层面对系统SEH机制的封装 23.2.1 扩展的EXCEPTION_REGISTRATION级相关结构:VC_EXCEPTION_REGISTRATION (1)VC_EXCEPTIO ...