• s3c2410 board.c分析


    串口中打印出来的信息大多数来自board.c文件。

    在介绍该函数之前,我们需要看一看几个数据结构,这些是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
    #if 0
    unsigned long cpu_clk; /* CPU clock in Hz! CPU
    的时钟频率*/
    unsigned long bus_clk; //
    总线的时钟频率
    unsigned long ram_size; /* RAM size, RAM
    的大小*/
    unsigned long reset_status; /* reset status register at boot */
    #endif
    void  **jt;  /* jump table ,
    保存着些函数的入口地址,common/Exports.c中进行填充*/
    } gd_t;
    2
    )、bd_t 保存与板子相关的配置参数
    typedef struct bd_info

    {
        int            bi_baudrate;    /* serial console baudrate ,
    串口波特率 */
        unsigned long    bi_ip_addr;    /* IP Address ,IP
    地址*/
        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; //RAM
    的起始地址
             ulong size; //RAM
    的大小
        }            

    bi_dram[CONFIG_NR_DRAM_BANKS];
    } bd_t;
    3). 
    初始化函数列表(以数组的形式)
    init_fnc_t *init_sequence[] =

    {

    cpu_init,   /* basic cpu dependent setup  || cpu/arm920t/cpu.c ,cpu的初始化,有待于分析*/
    //
    这个是对板子的初始化,
    board_init,   /* basic board dependent setup|| board/smdk2440/smdk2440.c */
    interrupt_init,  /* set up exceptions || cpu/arm920t,s3c24x0/interrupts.c */
    env_init,   /* initialize environment */
    init_baudrate,  /* initialze baudrate settings */
    serial_init,  /* serial communications setup || cpu/arm920t/s3c24x0/serial.c */
    //
    串口初始化后我们就可以打印信息了 
    console_init_f,  /* stage 1 init of console */
    display_banner,  /* say that we are here */
    #if defined(CONFIG_DISPLAY_CPUINFO)
    print_cpuinfo,  /* display cpu info (and speed) */
    #endif
    #if defined(CONFIG_DISPLAY_BOARDINFO)
    checkboard,  /* display board info */
    #endif
    dram_init,  /* configure available RAM banks */
    display_dram_config,
    NULL,
    };
    //===========================================
    int cpu_init (void) //cpu/arm920t/Cpu.c
    中的函数
    {
    /*
      * setup up stacks if necessary
      */
    //
    这里只是做了对中断栈和快速中断栈空间地址的定义
    //IRQ_STACK_START 
     FIQ_STACK_START 的值在start.S的开始几行中有定义
    //
    其中的那个 -4 操作是难道是为PC跳转留的一个地址???
    #ifdef CONFIG_USE_IRQ
    IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
    FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
    #endif
    return 0;
    }
    //===================================================
    //---------mem_malloc_init----------------
    //  
    参数: malloc内在区的起始地址 
    //  
    功能完成malloc函数所要用到的静态变量的初始化.
    //
    返回值:   
    //----------------------------------------

    static void mem_malloc_init (ulong dest_addr)
    {
    mem_malloc_start = dest_addr; //
    缓冲区起始地址 
    mem_malloc_end = dest_addr + CFG_MALLOC_LEN; // 
    缓冲区结束地址 
    mem_malloc_brk = mem_malloc_start; // 
    已使用块的地址,初始时应指向起始地址 
    memset ((void *) mem_malloc_start, 0, mem_malloc_end - mem_malloc_start); //
    把这段空间初始化为0
    }
    ......
    init_fnc_t *init_sequence[] = {
    //
    该函数只是做了对中断栈和快速中断栈空间地址的定义
    cpu_init,   /* basic cpu dependent setup  || cpu/arm920t/cpu.c */
    //
    完成各时钟和端口还有gd中的两个成员的初始化 
    board_init,   /* basic board dependent setup|| board/smdk2440/smdk2440.c */
    //PWM(Pulse Width Modulation 
    脉宽调制器) TIMER的初始化
    interrupt_init,  /* set up exceptions || cpu/arm920t,s3c24x0/interrupts.c */
    //
    环境的初始化,没深入分析 
    env_init,   /* initialize environment */
    //
    初始化波特率,并写进gd的成员变量中 
    init_baudrate,  /* initialze baudrate settings */

    //
    串口初始化后我们就可以打印信息了 
    serial_init,  /* serial communications setup || cpu/arm920t/s3c24x0/serial.c */

    console_init_f,  /* stage 1 init of console */

    //
    打印一些信息 
    display_banner,  /* say that we are here */
    #if defined(CONFIG_DISPLAY_CPUINFO)
    print_cpuinfo,  /* display cpu info (and speed) */
    #endif
    #if defined(CONFIG_DISPLAY_BOARDINFO)
    checkboard,  /* display board info */
    #endif
    //DRAM
    的初始化,这里只是对gd中的 bi_dram结构中的两个成员赋值,
    //
    也即BANK的起始地址和大小 
    dram_init,  /* configure available RAM banks */

    //
    打印BANK的相关信息
    display_dram_config,
    NULL, //
    用以标识列表数组的结束 
    };
    //------------start_armboot-------------------- 
    //
    功能完成uboot第二阶级的一系列的硬件初始化工作然后转入main函数
    //
    备注该函数是C程序的入口函数,从汇编语言跳转到此 . 
    //--------------------------------------------- 
    void start_armboot (void)
    {
        init_fnc_t **init_fnc_ptr; //init_fnc_t 
    是各初始化函数的数组 
        char *s;
    #ifndef CFG_NO_FLASH
        ulong size;
    #endif
    #if defined(CONFIG_VFD) || defined(CONFIG_LCD)
        unsigned long addr;
    #endif
      /* Pointer is writable since we allocated a register for it 
          gd_t: 
    定义在 /include/asm-arm/Global_data.h,包含一些全局通用的变量
     
       _armboot_start: 代码的起始地址,它定义在start.S中的前几行中,定义为 _start 当系统第一次加电时,指令是从0x0地址开始执行的,所以此时的_start值应为0x0;而当uboot经过代码重定位后,指令会从 _TEXT_BASE处开始执行,此时的_start值就成了_TEXT_BASE的值.   CFG_MALLOC_LEN: /include/configs/smdk2440.h中有定义,该变量表示供malloc函数使用的内存池空间,代码中定义值为:0x10000+128*1024 
    |-------|<--- _armboot_start
    基址 
    |  4    |  
    |-------|<--- malloc
    函数池基址 
    |  3    | 
    |-------|<--- (gd_t)gd(
    全局变量表)基址
    |  2    | 
    |-------|<--- (bt_t)bd(
    板卡信息表)基址
    |  1    | 
      ------- 
       4 
    就是为malloc函数预留的数据空间 
       3 
    是全局信息表gd的数据区
      2 
    是板卡信息表bd的数据区 
    网上找了个图片,更能反应这个空间的分配关系

    */
         //
    分配区域 3  gd ,gd是一个全局静态变量 
        gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

    /* compiler optimization barrier needed for GCC >= 3.4 */
        __asm__ __volatile__("": : :"memory");
    //gd变量的内容填充为0 ,填充 3 区的数据为0 ,即初始化gd.注意:这里并没有初始化bd,gd表中的bd成员只是一个指针,因为对初始化的是个指针地址 
        memset ((void*)gd, 0, sizeof (gd_t));
    /*  bd_t 结构体在/include/asm-arm/U-boot.h中定义定义板子的一些信息,包括:
      
    波特率,IP地址以太网地址架构编码,启动参数 ,BANK的起始地址和大小等 */ 
    //
    分配区域 2 bd, bd的基址 = gd的基址 - bd的尺寸 
        gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
    //把区域 2 填充为 0 ,即初始化 bd  
        memset (gd->bd, 0, sizeof (bd_t));
    /*monitor_falsh_len定义在 /lib_arm/Board.c
    bin文件中 BSS 段和 TEXT 段和 DATA 段存放的顺序同前向后依次是:
      TEXT(
    代码段 RO)    DATA(已初始化数据段 RW)   BSS(未初始化数据段 ZI) 
    所以 _bss_start 的基址等于 TEXT的长度加上DATA的长度.
    : _bss_start(BSS段基址) = 代码段长度+数据段长度 

    BSS(Block Started by Symbol)
    段是未被初始化的数据段,是存放程序中未被初始化的全局变量的一块内存区域,初始化时应清零;该段只有名称和大小却没有值;该段不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效地清零,它在应用程序的映像文件(ARM中也即bin文件)中并不存在
    text :
    代码段,是包含程序代码的段
    data  :
    已经初始化的数据段,保存已经初始化的全局变量
        
    在嵌入式系统中,bin文件(又称Image文件)中只包含textdatabss段不在其中,它是由系统初始化为零. */ 
      //_armboot_start 
    start.S中定义为_start,_start为代码的起始地址只包含 RO(TEXT)  RW(DATA) .重定位前的值为0x0,此时指向flash,重定位后则指向RAM中的某一地址由此可以知道:  _bss_start - _armboot_start 的值即是在第一阶段从flash中重定位到RAM中的那部分代码的长度,也即可TEXTDATA,这个值与start.S中的重定位那部分代码所计算的值是相等的;所以,monitor_flash_len表示从flash中搬来的代码的长度 
        monitor_flash_len = _bss_start - _armboot_start;  //_bss_start 
    u-boot.lds中定位 
    //
    各设置的初始化.当返回值不为0时表示初始化失败 ,此时会调用hang()函数
    //打印一错误提示信息,然后进入死循环 
        for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
            if ((*init_fnc_ptr)() != 0) {
                hang ();
            }
        }
    //CFG_NO_FLASH 表示没有flash,如果没定义该常量则表示板子上有flash,此时调用flash_init()对其进行初始化.
    #ifndef CFG_NO_FLASH
       
     /* configure available FLASH banks */
        size = flash_init ();
        display_flash_config (size); 
    //打印flash的信息,这里仅输出它的大小 
    #endif /* CFG_NO_FLASH */
    #ifdef CONFIG_VFD
    #   ifndef PAGE_SIZE
    #     define PAGE_SIZE 4096
    #   endif
         
    /*
          * reserve memory for VFD display (always full pages)
          */
        /* bss_end is defined in the board-specific linker script */

      
     //把视频帧缓冲区设置在bss_end后面

    addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); 
        size = vfd_setmem (addr);
        gd->fb_base = addr; 
    //fb_base base address of frame buffer


    #endif /* CONFIG_VFD */


    #ifdef CONFIG_LCD
    # ifndef PAGE_SIZE
    #   define PAGE_SIZE 4096
    # endif
         /*
          * reserve memory for LCD display (always full pages)
          *///
    LCD分配RAM(内存)空间 
         /* bss_end is defined in the board-specific linker script */

        addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
        size = lcd_setmem (addr);
        gd->fb_base = addr; //
    为显存缓冲区地址变量赋值 
    #endif /* CONFIG_LCD */
    /* armboot_start is defined in the board-specific linker script */
    //malloc
    函数使用缓冲区的初始化
        mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);  
    //
    如果定义了命令和NAND命令,则初始化nand 
    #if (CONFIG_COMMANDS & CFG_CMD_NAND)
        puts ("NAND:  ");
        nand_init();  /* go init the NAND */
    #endif
    #ifdef CONFIG_HAS_DATAFLASH
        AT91F_DataflashInit();
        dataflash_print_info();
    #endif
         /* initialize environment 
    环境的初始化,代码在common/env_common.c */
        env_relocate ();
    #ifdef CONFIG_VFD
         /* must do this after the framebuffer is allocated */
        drv_vfd_init();
    #endif /* CONFIG_VFD */
         /* IP Address 
    为全局变量的成员赋值:IP地址*/
    gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");//ipaddrsmdk2440.h中的CONFIG_IPADDR中出现,应该是该常量 
    /* MAC Address *///
    高处MAC地址 ,并赋给gd的成员变量 
    {
        int i;
        ulong reg;
        char *s, *e;
        char tmp[64];
        i = getenv_r ("ethaddr", tmp, sizeof (tmp));
        s = (i > 0) ? tmp : NULL;
        for (reg = 0; reg < 6; ++reg) {
        gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
        if (s)
            s = (*e) ? e + 1 : e;
    }
    #ifdef CONFIG_HAS_ETH1
      i = getenv_r ("eth1addr", tmp, sizeof (tmp));
      s = (i > 0) ? tmp : NULL;
      for (reg = 0; reg < 6; ++reg) {
       gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
       if (s)
        s = (*e) ? e + 1 : e;
      }
    #endif
    }

    devices_init (); /* get the devices list going. */
    #ifdef CONFIG_CMC_PU2
    load_sernum_ethaddr ();
    #endif /* CONFIG_CMC_PU2 */
    //
    初始化跳转表,gd中的jt(函数跳转表)数组进行初始化,其中保存着一些函数的入口地址 
    jumptable_init ();
      
    console_init_r (); /* fully init console as a device 
    我没具体分析内部实现*/
    #if defined(CONFIG_MISC_INIT_R)
    /* miscellaneous platform dependent initialisations, miscellaneous:
    各色各样混在一起混杂的*/ 
    misc_init_r ();
    #endif
    /* enable exceptions 
    设置cpsrIF位以充许中断*/
    enable_interrupts ();
    /* Perform network card initialisation if necessary */
    #ifdef CONFIG_DRIVER_CS8900
    cs8900_get_enetaddr (gd->bd->bi_enetaddr);
    #endif
    #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, 16);
    }
    #if (CONFIG_COMMANDS & CFG_CMD_NET)
    if ((s = getenv ("bootfile")) != NULL) {
      copy_filename (BootFile, s, sizeof (BootFile));
    }
    #endif /* CFG_CMD_NET */
    #ifdef BOARD_LATE_INIT
    board_late_init ();
    #endif
    #if (CONFIG_COMMANDS & CFG_CMD_NET)
    #if defined(CONFIG_NET_MULTI)
    puts ("Net:   ");
    #endif
    eth_initialize(gd->bd);
    #endif
    /* main_loop() can return to retry autoboot, if so just run it again. */
    //
    直接进入main_loop 该函数在common/main.c
    //!!!!!!!!
    至此,硬件初始化完成
    for (;;) {
      main_loop ();


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

  • 相关阅读:
    刷题总结——跳蚤(poj1091容斥+分解质因数)
    刷题总结——分糖(ssoj 容斥原理+逆元+快速幂+组合数求插板)
    刷题总结——旅馆(bzoj1593线段树)
    刷题总结——树的同构(bzoj4337 树上hash)
    刷题总结——骑士的旅行(bzoj4336 树链剖分套权值线段树)
    刷题总结——松鼠的新家(bzoj3631)
    mysql备份与恢复
    nginx添加用户验证(访问服务器是的用户名密码)
    df命令
    org.mongodb.morphia.query.QueryException: sorting is not allowed for updates.
  • 原文地址:https://www.cnblogs.com/killer-xc/p/4384191.html
Copyright © 2020-2023  润新知