一来到void start_armboot (void)函数,马上出现两个很重要的数据结构gd_t和bd_t

1、gd_t : global data数据结构定义,位于文件 include/asm-arm/global_data.h。其成员主要是一些全局的系统初始化参数。

[cpp] view
plain
?
  1. typedef struct  global_data {
  2. bd_t        *bd;      // struct board_info<span style="font-family:宋体;">指针,保存板子信息</span>
  3. unsigned long   flags;     // <span style="font-family:宋体;">指示标志,如设备已经初始化标志等</span>
  4. unsigned long   baudrate;
  5. unsigned long   have_console;   /* serial_init() was called */
  6. unsigned long   reloc_off;  /* Relocation Offset */
  7. unsigned long   env_addr;   /* Address  of Environment struct 环境参数地址*/
  8. unsigned long   env_valid;  /* Checksum of Environment valid? */
  9. unsigned long   fb_base;    /* base address of frame buffer */
  10. #ifdef CONFIG_VFD
  11. unsigned char   vfd_type;   /* display type */
  12. #endif
  13. #if 0
  14. unsigned long   cpu_clk;    /* CPU clock in Hz!     */
  15. unsigned long   bus_clk;
  16. unsigned long   ram_size;   /* RAM size */
  17. unsigned long   reset_status;   /* reset status register at boot */
  18. #endif
  19. void        **jt;       /* jump table */
  20. } gd_t;

2.、bd_t :board info数据结构定义,位于文件 include/asm-arm/u-boot.h。保存板子参数。

[cpp] view
plain
?
  1. typedef struct bd_info {
  2. int         bi_baudrate;    /* serial console baudrate */
  3. unsigned long   bi_ip_addr; /* IP Address */
  4. unsigned char   bi_enetaddr[6]; /* Ethernet adress */
  5. struct environment_s           *bi_env;
  6. ulong           bi_arch_number; /* unique id for this board  <span style="font-family:宋体;">板子</span><span style="font-family:Times New Roman;">ID</span><span style="font-family:宋体;">号</span>*/
  7. ulong           bi_boot_params; /* where this board expects params */
  8. struct              /* RAM configuration */
  9. {
  10. ulong start;
  11. ulong size;
  12. }           bi_dram[CONFIG_NR_DRAM_BANKS];
  13. #ifdef CONFIG_HAS_ETH1
  14. /* second onboard ethernet port */
  15. unsigned char   bi_enet1addr[6];
  16. #endif
  17. } bd_t;

分配一个存储全局数据的区域,地 址给指针 gd

[cpp] view
plain
?
  1. gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

清0并分配空间

[cpp] view
plain
?
  1. memset ((void*)gd, 0, sizeof (gd_t));

在gd前面的位置给 gd->bd赋值地址

[cpp] view
plain
?
  1. gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

清0并分配空间

[cpp] view
plain
?
  1. memset (gd->bd, 0, sizeof (bd_t));

执行一系列初始化函数

[cpp] view
plain
?
  1. for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  2. if ((*init_fnc_ptr)() != 0) {
  3. hang ();
  4. }
  5. }

假如函数指针指向的函数返回值不为0,那么在hang()里就会死循环,初始化失败

[cpp] view
plain
?
  1. void hang (void)
  2. {
  3. puts ("### ERROR ### Please RESET the board ###\n");
  4. for (;;);
  5. }

函数列表如下:

每个初始化函数正常情况下返回值是0

[cpp] view
plain
?
  1. init_fnc_t *init_sequence[] = {
  2. cpu_init,  /* 初始化irq/fiq模式的栈*/
  3. board_init, /* 设置系统时钟*/
  4. interrupt_init, /*初始化定时器*/
  5. env_init,  /* 检查flash上的环境参数是否有效*/
  6. init_baudrate, /* 初始化波特率*/
  7. serial_init, /* 初始化串口*/
  8. console_init_f, /*初始化串口控制台*/
  9. display_banner, /* say that we are here */

接着进行一些NOR FLASH,LCD,串口,控制台,sd卡,网卡等初始化,不一一列举了。

终于来到重要的时刻了 - -#

进入一个死循环

[cpp] view
plain
?
  1. for (;;)
  2. {
  3. main_loop ();
  4. }

继续跟踪

发现在bootdelay时间内按下键进入命令行,用run_command来解析命令

[cpp] view
plain
?
  1. #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
  2. s = getenv ("bootdelay");
  3. bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
  4. debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);

如果CONFIG_BOOTDELAY已经定义,用s得到环境变量bootdelay,然后倒数启动内核

[cpp] view
plain
?
  1. #ifdef CONFIG_BOOTCOUNT_LIMIT
  2. if (bootlimit && (bootcount > bootlimit)) {
  3. printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
  4. (unsigned)bootlimit);
  5. s = getenv ("altbootcmd");
  6. }
  7. else
  8. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  9. s = getenv ("bootcmd");

CONFIG_BOOTCOUNT_LIMIT是设置u-boot启动次数的限制

最后s = getenv ("bootcmd");获得启动参数

[cpp] view
plain
?
  1. run_command (s, 0);

启动命令解析

在run_command 函数里最终执行命令

[cpp] view
plain
?
  1. /* OK - call function to do the command */
  2. if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
  3. rc = -1;
  4. }

这是一个命令结构体,原型如下:

[cpp] view
plain
?
  1. struct cmd_tbl_s {
  2. char        *name;      /* Command Name         */
  3. int     maxargs;             /* 最大的参数个数 */
  4. int     repeatable; /* 命令可否重复   */
  5. int     (*cmd)(struct cmd_tbl_s *, int, int, char *[]);/*对应的函数指针*/
  6. char        *usage;     /* Usage message    (short) */

正常情况下就会执行U_BOOT_CMD命令,U_BOOT_CMD宏定义一个命令,命令宏原型如下:

[cpp] view
plain
?
  1. /*命令宏U_BOOT_CMD*/
  2. #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
  3. cmd_tbl_t    __u_boot_cmd_##name     Struct_Section = {#name, maxargs, rep, cmd, usage, help}

假若上面是传入的是一个bootm命令启动内核,将会调用相应的

 U_BOOT_CMD里的do_bootm函数
[cpp] view
plain
?
  1. U_BOOT_CMD(
  2. bootm,  CFG_MAXARGS,    1,  do_bootm,
  3. "bootm   - boot application image from memory\n",
  4. "[addr [arg ...]]\n    - boot application image stored in memory\n"
  5. "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
  6. "\t'arg' can be the address of an initrd image\n"

在do_bootm函数里,将用switch case检查内核zImage类型,解压方式,操作系统等,因为zImage是自解压的,不用解压

[cpp] view
plain
?
  1. switch (hdr->ih_os) {
  2. default:            /* handled by (original) Linux case */
  3. case IH_OS_LINUX:
  4. do_bootm_linux  (cmdtp, flag, argc, argv,
  5. addr, len_ptr, verify);
  6. break;

最后,将进入Armlinux.c的do_bootm_linux函数启动Linux内核



U_Boot也是通过标记列表向内核传递参数的

[cpp] view
plain
?
  1. #ifdef CONFIG_CMDLINE_TAG
  2. char *commandline = getenv ("bootargs");
  3. #endif

CONFIG_CMDLINE_TAG在smdk2410.h里已经定义了

theKernel指向内核 存放的地址,(对于ARM架构的CPU,通常是0x30008000),

/*声明内核的入口函数指针*/

[cpp] view
plain
?
  1. void (*theKernel)(int zero, int arch, uint params);

/*把内核入口地址赋值给theKernel,hdr是image_header_t结构体,指向uImage头部 ,ih_ep是内核的入口点(Entry Point)*/

[cpp] view
plain
?
  1. theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

/*最后是对内核入口函数的调用,bd->bi_arch_number是这个板子机器类型ID, bd->bi_boot_params是传给内核的参数,从标记列表地址开始*/

[cpp] view
plain
?
  1. theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
[cpp] view
plain
?
  1. 引导Linux内核启动的必须要满足的几个条件:
[cpp] view
plain
?
  1. * CPU register settings //这里也就是我们的theKernel中的作用
  2. o r0 = 0.
  3. o r1 = machine type number.
  4. o r2 = physical address of tagged list in system RAM.
  5. * CPU mode
  6. o All forms of interrupts must be disabled (IRQs and FIQs.)
  7. o The CPU must be in SVC mode. (A special exception exists for Angel.)
  8. * Caches, MMUs
  9. o The MMU must be off.
  10. o Instruction cache may be on or off.
  11. o Data cache must be off and must not contain any stale data.
  12. * Devices
  13. o DMA to/from devices should be quiesced.
  14. * The boot loader is expected to call the kernel image by jumping directly to the first instruction of the kernel image.

U-boot分析与移植(3)----U-boot stage2分析的更多相关文章

  1. 【转】U-boot分析与移植(1)----bootloader分析

    原文网址:http://blog.csdn.net/jianchi88/article/details/7061089  一.Boot Loader 概念 就是在操作系统内核运行之前运行的一段小程序. ...

  2. U-boot分析与移植(1)----bootloader分析

    一.Boot Loader 概念 就是在操作系统内核运行之前运行的一段小程序.通过这段小程序,我们可以初始化硬件设备.建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作 ...

  3. spring boot实战(第十三篇)自动配置原理分析

    前言 spring Boot中引入了自动配置,让开发者利用起来更加的简便.快捷,本篇讲利用RabbitMQ的自动配置为例讲分析下Spring Boot中的自动配置原理. 在上一篇末尾讲述了Spring ...

  4. 《深入实践Spring Boot》阅读笔记之三:核心技术源代码分析

    刚关注的朋友,可以回顾前两篇文章: 基础应用开发 分布式应用开发 上篇文章总结了<深入实践Spring Boot>的第二部分,本篇文章总结第三部分,也是最后一部分.这部分主要讲解核心技术的 ...

  5. spring Boot(十九):使用Spring Boot Actuator监控应用

    spring Boot(十九):使用Spring Boot Actuator监控应用 微服务的特点决定了功能模块的部署是分布式的,大部分功能模块都是运行在不同的机器上,彼此通过服务调用进行交互,前后台 ...

  6. Spring Boot (十): Spring Boot Admin 监控 Spring Boot 应用

    Spring Boot (十): Spring Boot Admin 监控 Spring Boot 应用 1. 引言 在上一篇文章<Spring Boot (九): 微服务应用监控 Spring ...

  7. Spring Boot高频面试题:Spring Boot执行原理

    之前一篇文章Spring Boot快速入门文章中,我们已经体会到Spring Boot的神器,不再像之前Spring那样需要繁琐的XML,甚至几秒钟就能搭建出Spring的项目骨架.接下来我们简单分析 ...

  8. Linux之uboot分析与移植20160601

    说一下uboot分析与移植: 1.下载.建立source insight工程.编译.烧写.如果无运行分析原因 tar xjf u-boot-2012.04.01.tar.bz2 cd u-boot-2 ...

  9. 基于Petri网的工作流分析和移植

    基于Petri网的工作流分析和移植 一.前言 在实际应用场景,包括PEC的订单流程从下订单到订单派送一直到订单完成都是按照一系列预先规定好的工作流策略进行的. 通常情况下如果是采用面向过程的编程方法, ...

  10. spring boot系列01--快速构建spring boot项目

    最近的项目用spring boot 框架 借此学习了一下 这里做一下总结记录 非常便利的一个框架 它的优缺点我就不在这背书了 想了解的可以自行度娘谷歌 说一下要写什么吧 其实还真不是很清楚,只是想记录 ...

随机推荐

  1. 新东方雅思词汇---8.2、chron

    新东方雅思词汇---8.2.chron 一.总结 一句话总结:时间 chronic 英 ['krɒnɪk]  美 ['krɑnɪk]  adj. 慢性的:长期的:习惯性的 n. (Chronic)人名 ...

  2. InflateException:Bin file line #19:Error inflating class MyTextView

    InflateException:Bin file line #19:Error inflating class MyTextView 一.错误简介 为了实现TextView的跑马灯效果,我自己写了一 ...

  3. 四十一 Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)基本的索引和文档CRUD操作、增、删、改、查

    elasticsearch(搜索引擎)基本的索引和文档CRUD操作 也就是基本的索引和文档.增.删.改.查.操作 注意:以下操作都是在kibana里操作的 elasticsearch(搜索引擎)都是基 ...

  4. Spring 自动装配;方法注入

    通过配置defalut—autowire属性,Spring IOC容器可以自动为程序注入Bean:默认是no(不启用自动装配). default—autowire的类型有: byName:通过名称自动 ...

  5. 2017.11.24 Stm8L151-factory

    Marking---------factory fun... /** ***************************************************************** ...

  6. [置顶] Kubernetes1.7新特性:新增自动伸缩条件和参数

    一.核心概念 Horizontal Pod Autoscaling,简称HPA,是Kubernetes中实现POD水平自动伸缩的功能.云计算具有水平弹性的特性,这个是云计算区别于传统IT技术架构的主要 ...

  7. 【MFC】CDC::BitBlt介绍

    CDC::BitBlt介绍 2011-11-04 08:25 19576人阅读 评论(6) 收藏 举报 摘自: http://blog.csdn.net/bberdong/article/detail ...

  8. 查看 nginx 的并发连接数

    通过查看Nginx的并发连接,我们可以更清除的知道网站的负载情况.Nginx并发查看有两种方法(之所以这么说,是因为笔者只知道两种),一种是通过web界面,一种是通过命令,web查看要比命令查看显示的 ...

  9. ACM学习历程—计蒜客15 单独的数字(位运算)

    http://nanti.jisuanke.com/t/15 题目要求是求出只出现一次的数字,其余数字均出现三次. 之前有过一个题是其余数字出现两次,那么就是全部亦或起来就得到答案. 这题有些不太一样 ...

  10. jQuery火箭图标返回顶部代码

    在网上找来段使用jQuery火箭图标返回顶部代码,感觉比较酷,比较炫,大概样式如下, 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. ...