热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

U-Boot系列之四:start_armboot()函数分析

nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd
在上一篇2011-08/39958.htm文章中,我们介绍了u-boot启动的时候汇编语言的部分,当时我们进行了一些简单的初始化,并且为C语言的执行建立的环境(堆栈),现在我们看看当从汇编语言转到C语言的时候执行的第一个函数( start_armboot (),在lib_arm\board.c中),该函数进行了一系列的外设初始化,然后调用main_loop (),根据配置来选择是直接加载Linux内核还是进入等待命令模式。

    在介绍该函数之前,我们需要看一看几个数据结构,这些是u-boot中几个重要的数据结构:

1)、gd_t该数据结构保存了u-boot需要的配置信息,注释简单明了
typedef    struct    global_data {
    bd_t        *bd; //与板子相关的结构,见下面
    unsigned long    flags;
    unsigned long    baudrate;
    unsigned long    have_console;    /* serial_init() was called */
    unsigned long    reloc_off;    /* Relocation Offset */
    unsigned long    env_addr;    /* Address  of Environment struct */
    unsigned long    env_valid;    /* Checksum of Environment valid? */
#ifdef CONFIG_VFD  //我们一般没有配置这个,这个是frame buffer的首地址
    unsigned long    fb_base;    /* base address of frame buffer */
#endif
} gd_t;

2)、bd_t 保存与板子相关的配置参数
typedef struct bd_info {
    int            bi_baudrate;    /* serial console baudrate */
    unsigned long    bi_ip_addr;    /* IP Address */
    unsigned char    bi_enetaddr[6]; /* Ethernet adress */
    struct environment_s           *bi_env;
    ulong            bi_arch_number;    /* unique id for this board */
    ulong            bi_boot_params;    /* where this board expects params */
    struct                /* RAM configuration */
    {
    ulong start;
    ulong size;
    }             bi_dram[CONFIG_NR_DRAM_BANKS];//在我的板子上是1个
} bd_t;

现在我贴出start_armboot ()的源代码,然后具体的在其中解释一些代码的作用:


void start_armboot (void)
{
    DECLARE_GLOBAL_DATA_PTR;

    ulong size;
    gd_t gd_data;
    bd_t bd_data;
    init_fnc_t **init_fnc_ptr; //这个是函数的指针,指向一些硬件初始化的函数,见下面
   
                    //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 */
                       //     display_banner,
                       //     dram_init,        /* configure available RAM banks */
                       //     display_dram_config,
                       //     NULL,
                       //     };

    //printf("**********Start *************\n");
    /* Pointer is writable since we allocated a register for it */
    gd = &gd_data;
    memset (gd, 0, sizeof (gd_t));//初始化为0
    gd->bd = &bd_data;
    memset (gd->bd, 0, sizeof (bd_t));//初始化为0

//注意,下面的循环是依次调用各个硬件初始化函数,顺序见上面的的数组,我们在下一篇中依次解释每种硬//件的初始化,第六个就是串口的初始化,这时候我们就可以通过串口输出信息了
    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();      //如果不成功的话,就“输出信息,然后就进入死循环”
        }
    }

    /* configure available FLASH banks */
    size = flash_init ();  //flash的初始化
    display_flash_config (size);//打印flash的配置信息

    /* initialize environment */
    env_relocate ();//环境的初始化,代码在common\env_common.c中

    /* IP Address */
    bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");//读取IP地址,保存到bd_t数据结构中

    /* MAC Address */ //MAC地址的初始化
    {
        int i;
        ulong reg;
        char *s, *e;
        uchar tmp[64];

        i = getenv_r ("ethaddr", tmp, sizeof (tmp));
        s = (i > 0) ? tmp : NULL;

        for (reg = 0; reg <6; ++reg) {
            bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
            if (s)
                s = (*e) ? e + 1 : e;
        }
    }


    /* enable exceptions */  //允许中断
    enable_interrupts ();

#ifdef CONFIG_DRIVER_CS8900  //配置网卡
    if (!getenv ("ethaddr")) {
        cs8900_get_enetaddr (gd->bd->bi_enetaddr);
    } 
#endif

//直接进入main_loop 该函数在common\main.c中,至此,硬件初始化完成
    /* main_loop() can return to retry autoboot, if so just run it again. */
    for (;;) {
        main_loop ()
    }

    /* NOTREACHED - no way out of command loop except booting */
}

呵呵,好像很简单哦,其实我们并没有深入下去,只是在水面上来高屋建瓴,目的就是让大家有一个整体的映像,然后再根据start_armboot()中的初始化步骤来一个一个解释每种硬件的初始化。依次是cpu_init、board_init、interrupt_init、env_init、init_baudrate、serial_init、dram_init、flash_init等。
推荐阅读
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 流数据流和IO流的使用及应用
    本文介绍了流数据流和IO流的基本概念和用法,包括输入流、输出流、字节流、字符流、缓冲区等。同时还介绍了异常处理和常用的流类,如FileReader、FileWriter、FileInputStream、FileOutputStream、OutputStreamWriter、InputStreamReader、BufferedReader、BufferedWriter等。此外,还介绍了系统流和标准流的使用。 ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 如何使用Python从工程图图像中提取底部的方法?
    本文介绍了使用Python从工程图图像中提取底部的方法。首先将输入图片转换为灰度图像,并进行高斯模糊和阈值处理。然后通过填充潜在的轮廓以及使用轮廓逼近和矩形核进行过滤,去除非矩形轮廓。最后通过查找轮廓并使用轮廓近似、宽高比和轮廓区域进行过滤,隔离所需的底部轮廓,并使用Numpy切片提取底部模板部分。 ... [详细]
author-avatar
城隍山人因
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有