学习目标:

1、分析u-boot-1.1.6第2阶段入口函数void start_armboot (void),熟悉该函数所实现的功能

2、为后面能够掌握u-boot-1.1.6如何启动内核过程打下基础


前面通过对uboot第一阶段代码的分析,我们了解的uboot第一阶段所做的一些工作,并且找到了其第二阶段的入口函数void start_armboot(void)。为了能够在清楚理解uboot启动内核的机制,还需要对第二阶段代码进行分析。第二阶段入口函数void start_armboot(void)存放在board.c文件中,该文件位于uboot根目录下的lib_arm文件夹中。

1.gd_t数据结构分配内存

/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); //为gd_t结构体变量开辟空间
/* compiler optimization barrier needed for GCC >= 3.4 */ //并使得gd指针指向该空间初始位置
__asm__ __volatile__("": : :"memory"); memset ((void*)gd, , sizeof (gd_t)); //gd获取内存块清零
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); //为bd_t结构体变量开辟空间,并使得gd->bd指针指向bd_t的初始位置
memset (gd->bd, , sizeof (bd_t)); //bd_t内存范围清零

start_armboot函数首先为gd_t数据类型分配相应的内存空间,并使得gd指针指向这块内存空间。gd指针在global_data.h文件(位于uboot根目录下的include/asm-arm文件夹)中声明,在start_armboot函数中定义,声明形式为:

  #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

这个声明告诉编译器使用CPU寄存器r8来存储gd_t类型的指针gd,即这个定义声明了一个指针,并且指明了它的存储位置。register表示变量放在机器的寄存器,volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次使用直接读值。gd_t数据结构紧接在uboot自定义的堆区域下的全局变量区域进行存放,分配完成后使用memset函数对这块内存进行清零,uboot存储器映射图如下所示:

2.硬件的初始化

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != ) {
hang ();
}
}

init_fnc_ptr是在start_armboot函数中定义的局部变量,该变量是一个二级指针,指向int (init_fnc_t) (void)类型函数的指针。init_sequence是一个指针数组的名称,指针数组init_sequence[]存放硬件初始化函数的地址。使用这种方式调用函数的好处是如果要添加初始化一些新的硬件时,只需写出新硬件初始化函数,将编写初始化函数名放在init_sequence[]中,不用修改其他代码,便能调用新的硬件初始化函数。指针数组内容如下:

init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
/* 未定义CONFIG_DISPLAY_CPUINFO宏,print_cpuinfo不被编译 */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
/* 未定义CONFIG_DISPLAY_BOARDINFO宏,checkboard不被编译 */
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
dram_init, /* configure available RAM banks */
display_dram_config,
NULL,
};

cpu_init函数功能:如果配置文件使能IRQ中断和FIQ中断,那么就获取uboot存储器映射中IRQ、FIQ堆栈的地址,将其保存在全局变量IRQ_STACK_START和FIQ_STACK_START中。

board_init函数功能:设置系统时钟,初始化相应的GPIO端口,设置全局变量gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;(arch number of SMDK2410-Board),gd->bd->bi_boot_params =   0x30000100(传给内核启动参数的地址),使能指令缓存和数据缓存。

interrupt_init函数功能:初始化系统定时器

env_init函数功能:从flash中读取环境变量并进行crc校验,校验成功使用flash中环境变量的地址,校验失败使用默认环境变量的地址gd->env_addr  = (ulong)&default_environment[0];

init_baudrate函数功能:读取环境变量中波特率的值

serial_init函数功能:根据读取的波特率数值初始化串口

console_init_f函数功能:设置串口控制台

display_banner函数功能:串口打印uboot版本信息,以及uboot代码段、bss段链接地址

dram_init函数功能:将sdram起始地址和大小存入gt指针所指向全局变量 gd->bd->bi_dram[0].start = PHYS_SDRAM_1;gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

display_dram_config函数功能:串口打印sdram其实地址和大小的信息

3.初始化nor flash和nand flash

/* 未定义CFG_NO_FLASH宏,执行flash_init()初始化函数,打印flash容量 */
#ifndef CFG_NO_FLASH
/* configure available FLASH banks */
size = flash_init (); //读出板载flash大小
display_flash_config (size); //串口打印flash容量大小
#endif /* CFG_NO_FLASH */ /* 未定义CONFIG_VFD宏,不支持VFD液晶屏,此处代码不用分析 */
#ifdef CONFIG_VFD //液晶屏(不执行)
# ifndef PAGE_SIZE
# define PAGE_SIZE
# endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - )) & ~(PAGE_SIZE - );
size = vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */ /* 未定义CONFIG_LCD宏,不支持LCD液晶屏,此处代码不用分析 */
#ifdef CONFIG_LCD //液晶屏(不执行)
# ifndef PAGE_SIZE
# define PAGE_SIZE
# endif
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - )) & ~(PAGE_SIZE - );
size = lcd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_LCD */ /* 将malloc连接地址指定在指定内存位置 */
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); /* 未定义CFG_CMD_NAND宏,此处代码不被编译 */
#if (CONFIG_COMMANDS & CFG_CMD_NAND) //开发板是否板载nand flash,若对nand flash 进行初始化
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif

这段代码根据include/configs/smdk2410.h文件中的配置宏,选择性编译代码,初始化nor flash和nand flash,并读出flash的大小,通过串口打印相关信息到控制台。

5.配置网络和使能中断

    devices_init ();    /* get the devices list going. */

/* 未定义CONFIG_CMC_PU2,此处代码不编译 */
#ifdef CONFIG_CMC_PU2
load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */ jumptable_init (); console_init_r (); /* fully init console as a device */ /* 未定义CONFIG_MISC_INIT_R,此处代码不编译 */
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif /* enable exceptions */
enable_interrupts (); /* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif /* 未定义CONFIG_DRIVER_SMC91111和CONFIG_DRIVER_LAN91C96,此处代码不编译 */
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
if (getenv ("ethaddr")) {
smc_set_mac_addr(gd->bd->bi_enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */ /* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, );
}
#if (CONFIG_COMMANDS & CFG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif /* CFG_CMD_NET */ /* 未定义BOARD_LATE_INIT,不编译此处代码 */
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif /* 未定义CFG_CMD_NET,此处不编译 */
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#endif

5.跳转到main_loop函数

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

start_armboot函数经过一系列初始化之后,会再次跳转到main_loop函数中执行后续的操作。

总结:start_armboot函数

1、在uboot存储映射的全局变量区为全局结构gt_t分配内存空间,并让全局指针gt指向该分配内存空间入口地址

2、完成一些硬件的初始化,例如:设置系统时钟和GPIO端口,使能指令Cache和数据Cache,设置串口,初始化flash等

3、读取后续过程使用的信息,将其存储到gt指针指向的gt_t结构的内存空间中

4、会再次跳转到main_loop函数中执行其他后续操作

u-boot-1.1.6第2阶段入口函数start_armboot分析的更多相关文章

  1. React组件生命周期-初始化阶段的函数执行顺序

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8& ...

  2. 【Beta阶段】M2事后分析

    先上照片,最后一次开会了啊... 计划 你原计划的工作是否最后都做完了? 如果有没做完的,为什么? 答:没有全部做完,到目前为止,我们的还有几个实验的报告生成功能没有上线.这几个实验的数据处理文件已经 ...

  3. (转)spring boot实战(第三篇)事件监听源码分析

    原文:http://blog.csdn.net/liaokailin/article/details/48194777 监听源码分析 首先是我们自定义的main方法: package com.lkl. ...

  4. spring boot actuator工作原理之http服务暴露源码分析

    spring boot actuator的官方文档地址:https://docs.spring.io/spring-boot/docs/current/reference/html/productio ...

  5. Spring Boot JDBC:加载DataSource过程的源码分析及yml中DataSource的配置

    装载至:https://www.cnblogs.com/storml/p/8611388.html Spring Boot实现了自动加载DataSource及相关配置.当然,使用时加上@EnableA ...

  6. 曹工说Spring Boot源码(18)-- Spring AOP源码分析三部曲,终于快讲完了 (aop:config完整解析【下】)

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  7. spring boot 入口源码分析

    public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); / ...

  8. SpringMVC初始化阶段流程源码分析

    1.都知道SpringMVC项目启动的时候都会初始化一个类:DispatcherServlet,看这个类的源码我们可以发现他其实就是一个servlet, 为什么这么说呢?请看: DispatcherS ...

  9. Spring Boot的自动配置原理及启动流程源码分析

    概述 Spring Boot 应用目前应该是 Java 中用得最多的框架了吧.其中 Spring Boot 最具特点之一就是自动配置,基于Spring Boot 的自动配置,我们可以很快集成某个模块, ...

随机推荐

  1. 网络 Internet 的发展

    Internet源于美国军方,那时制定了TCP/IP协议. 互联网的典型应用有:www,FTP,E-mail. WWW:World Wide Web,简称Web,又称全球网.万维网等. 网页,c/s架 ...

  2. linux 软件包 rpm命令之安装、更新、卸载、依赖

    软件包分类1.源码包2.二进制包二进制包是源码包编译后产生的文件..exe文件是适用于windows平台的二进制包:RPM包适用于redhat系列的二进制包:deb包是适用于ubuntu平台的二进制包 ...

  3. Django 模板语言 标签

    前言:django的模板语法基本和flask的jinja2基本一样.下面比较一下两个模板语法的区别. ------深度变量的查找(万能的句点号) 在 Django 模板中遍历复杂数据结构的关键是句点字 ...

  4. centos7 部署 汉化版 gitlab 10.0.2

    更新说明: 20171009:增加3.5的内容 20171008:整理出gitlab部署手册 =============================================== gitla ...

  5. MySQL binlog格式解析

    MySQL binlog格式解析   binlog想必大家都不陌生,在主从复制或者某些情况下的数据恢复会用到.由于binlog是二进制数据,要查看一般都借助mysqlbinlog工具.这篇笔记分析了b ...

  6. 开源作业调度框架 - Quartz.NET - 实战使用1

    简介: 第一步:下载Quartz.NET 下载Quartz.NET只需要打开网址选择适宜的版本进行下载解压缩即可. 目前最新版本是2.3.3,压缩包为6MB,不过鉴于国内网速.我还是加一下博客园的下载 ...

  7. December 01st 2016 Week 49th Thursday

    Life is a maze and love is a riddle. 生活是个迷宫,爱情是个谜语. I am lost in both. Can you provide me some guida ...

  8. IIS : Add the server variable name to the allowed server variable list.

    IIS下设置反向代理访问时报错:将服务器变量名添加到允许的服务器变量列表中. 1.打开IIS: 2.打开要添加变量的站点: 3.打开URL Rewrite: 4.在右列上,选择“查看服务器变量(Vie ...

  9. 基于easyui开发Web版Activiti流程定制器详解(四)——页面结构(下)

    题外话: 这两天周末在家陪老婆和儿子没上来更新请大家见谅!上一篇介绍了调色板和画布区的页面结构,这篇讲解一下属性区的结构也是定制器最重要的一个页面. 属性区整体页面结构如图:  在这个区域可以定义工作 ...

  10. 【python库安装问题解决】UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 121: invalid start byte

    好久没用python了...今天随便pip安装个库突然报错: Exception:‘’ (most recent call last):  File "C:\ProgramData\Anac ...