U-Boot移植(11)u-boot的重要细节

2023-08-28  

主要分析流程中各函数的功能。按启动顺序罗列一下启动函数执行细节。按照函数start_armboot流程进行分析:

    1)DECLARE_GLOBAL_DATA_PTR;

     这个宏定义在include/global_data.h中:

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

     声明一个寄存器变量 gd 占用r8。这个宏在所有需要引用全局数据指针gd_t *gd的源码中都有申明。

     这个申明也避免编译器把r8分配给其它的变量. 所以gd就是r8,这个指针变量不占用内存。

   2)gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

    对全局数据区进行地址分配,_armboot_start为0x3f000000,CFG_MALLOC_LEN是堆大小+环境数据区大小,configs/100ask24x0.h中CFG_MALLOC_LEN大小定义为192KB。

    3)gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

    分配板子数据区bd首地址。

    这样结合start.s中栈的分配,

    stack_setup:

    ldr r0, _TEXT_BASE  /* upper 128 KiB: relocated uboot   */

    sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */

    sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfoCFG_GBL_DATA_SIZE =128B */

    #ifdef CONFIG_USE_IRQ

    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

    #endif

    sub sp, r0, #12  /* leave 3 words for abort-stack    */

  不难得出上文所述的内存分配结构。

  下面几个函数是初始化序列表init_sequence[ ]中的函数:

  4)cpu_init();定义于cpu/arm920t/cpu.c

  分配IRQ,FIQ栈底地址,由于没有定义CONFIG_USE_IRQ,所以相当于空实现。

  5)board_init:板级初始化,定义于board/100ask24x0/100ask24x0.c

   设置PLL时钟,GPIO,使能I/D cache.

      设置bd信息:gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;//板子的ID,没啥意义。

           gd->bd->bi_boot_params = 0x30000100;//内核启动参数存放地址

    6)interrupt_init:定义于cpu/arm920t/s3c24x0/interrupt.c

     初始化2410的PWM timer 4,使其能自动装载计数值,恒定的产生时间中断信号,但是中断被屏蔽了用不上。

    7)env_init;定义于common/env_flash.c(搜索的时候发现别的文件也定义了这个函数,而且没有宏定义保证只有一个被编译,这是个问题,有高手知道指点一下!)

  功能:指定环境区的地址。default_environment是默认的环境参数设置。

   gd->env_addr  = (ulong)&default_environment[0];

   gd->env_valid = 0;

  8)init_baudrate;初始化全局数据区中波特率的值

  gd->bd->bi_baudrate = gd->baudrate =(i > 0)

   ? (int) simple_strtoul (tmp, NULL, 10)

   : CONFIG_BAUDRATE;

    9)serial_init; 串口通讯设置 定义于cpu/arm920t/s3c24x0/serial.c

     根据bd中波特率值和pclk,设置串口寄存器。

           10)console_init_f;控制台前期初始化common/console.c

    由于标准设备还没有初始化,(gd-> flags&GD_F*G_DEINIT=0)这时控制台使用串口作为控制台

    函数只有一句:gd->have_console = 1;

    11)dram_init,初始化内存RAM信息。board/100ask24x0/100ask24x0.c

    其实就是给gd->bd中内存信息表赋值而已。

     gd->bd->bi_dram[0].start = PHYS_SDRAM_1;

 gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

 初始化序列表init_sequence[]主要函数分析结束。

    12)flash_init;定义在board/100ask24x0/flash.c

    这个文件与具体平台关系密切,ylp2410使用的flash与FS2410不一样,所以移植时这个程序就得重写

    flash_init()是必须重写的函数,它做哪些操作呢?

    首先是有一个变量flash_info_t flash_info[CFG_MAX_FLASH_BANKS]来记录flash的信息。flash_info_t定义:

    typedef struct {

    ulong size;   /* 总大小BYTE  */

    ushort sector_count;  /* 总的sector数*/

    ulong flash_id;  /* combined device & manufacturer code */

    ulong start[CFG_MAX_FLASH_SECT];   /* 每个sector的起始物理地址。 */

    uchar protect[CFG_MAX_FLASH_SECT]; /* 每个sector的保护状态,如果置1,在执行erase操作的时候将跳过对应sector*/

     #ifdef CFG_FLASH_CFI //我不管CFI接口。

    .....

     #endif

   } flash_info_t;

   flash_init( )的操作就是读取ID号,ID号指明了生产商和设备号,根据这些信息设置size,sector_count,flash_id.以及start[]、protect[]。

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

     addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

   size = vfd_setmem (addr);

   gd->fb_base = addr;

  14)mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

   设置heap区,供malloc使用。下面的变量和函数定义在lib_arm/board.c

   malloc可用内存由mem_malloc_start,mem_malloc_end指定。而当前分配的位置则是mem_malloc_brk。

   mem_malloc_init负责初始化这三个变量。malloc则通过sbrk函数来使用和管理这片内存。

    static ulong mem_malloc_start = 0;

    static ulong mem_malloc_end = 0;

    static ulong mem_malloc_brk = 0;

    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);

    }

    void *sbrk (ptrdiff_t increment)

    {

     ulong old = mem_malloc_brk;

     ulong new = old + increment;

   

     if ((new < mem_malloc_start) || (new > mem_malloc_end)) {

      return (NULL);

     }

     mem_malloc_brk = new;

     return ((void *) old);

    }

  15)env_relocate(),环境参数区重定位

  由于初始化了heap区,所以可以通过malloc()重新分配一块环境参数区,

  但是没有必要,因为默认的环境参数已经重定位到RAM中了。

  /**这里发现个问题,ENV_IS_EMBEDDED是否有定义还没搞清楚,而且CFG_MALLOC_LEN也没有定义,也就是说如果ENV_IS_EMBEDDED没有定义则执行malloc,是不是应该有问题?**/

  16)IP,MAC地址的初始化。主要是从环境中读,然后赋给gd->bd对应域就OK。

  17)devices_init ();定义于common/devices.c

  int devices_init (void)//我去掉了编译选项,注释掉的是因为对应的编译选项没有定义。

   {

     devlist = ListCreate (sizeof (device_t));//创建设备列表

    i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);//初始化i2c接口,i2c没有注册到devlist中去。

    //drv_lcd_init ();

    //drv_video_init ();

    //drv_keyboard_init ();

    //drv_logbuff_init ();

    drv_system_init ();  //这里其实是定义了一个串口设备,并且注册到devlist中。

    //serial_devices_init ();

    //drv_usbtty_init ();

    //drv_nc_init ();

   }

经过devices_init(),创建了devlist,但是只有一个串口设备注册在内。显然,devlist中的设备都是可以做为console的。

18) jumptable_init ();初始化gd->jt。1.1.6版本的jumptable只起登记函数地址的作用。并没有其他作用。

19)console_init_r ();后期控制台初始化


参考:http://deshunfan.blog.163.com/blog/static/34244101200972832324749/#comment=fks_083066081081088066083081094095087082083071080087086066


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。