u-boot源码分析 --- 启动第二阶段003

看完初始化函数表,我们在顺着启动流程继续往下看,在来回顾下start_armboot的代码

 

lib_arm/Board.c:

void start_armboot (void)

{

    ……

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

    display_flash_config (size);

 

#ifdef CONFIG_VFD   //smdk2410没定义

#   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 */

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

    size = vfd_setmem (addr);

    gd->fb_base = addr;

#endif /* CONFIG_VFD */

 

#ifdef CONFIG_LCD  //smdk2410没定义

#   ifndef PAGE_SIZE

#     define PAGE_SIZE 4096

#   endif

    /*

     * reserve memory for LCD display (always full pages)

     */

    /* 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 */

……

}

 

我们接着看flash_init

board/smdk2410/flash.c:

ulong flash_init (void)

{

    int i, j;

    ulong size = 0;

 

    for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {

        ulong flashbase = 0;

 

        flash_info[i].flash_id =   /*保存flash ID*/

#if defined(CONFIG_AMD_LV400)

            (AMD_MANUFACT & FLASH_VENDMASK) |

            (AMD_ID_LV400B & FLASH_TYPEMASK);

#elif defined(CONFIG_AMD_LV800)

            (AMD_MANUFACT & FLASH_VENDMASK) |

            (AMD_ID_LV800B & FLASH_TYPEMASK);

#else

#error "Unknown flash configured"

#endif 

        /*保存每个flash blank的大小,sector数量,起始地址等信息*/

        flash_info[i].size = FLASH_BANK_SIZE;

        flash_info[i].sector_count = CFG_MAX_FLASH_SECT;

        memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);

        if (i == 0)

            flashbase = PHYS_FLASH_1;

        else

            panic ("configured too many flash banks!/n");

        for (j = 0; j < flash_info[i].sector_count; j++) {

            /*为每个sector分配不同的大小,作为不同的用途*/

            if (j <= 3) {

                /* 1st one is 16 KB */

                if (j == 0) {

                   flash_info[i].start[j] =

                       flashbase + 0;

                }

 

                /* 2nd and 3rd are both 8 KB */

                if ((j == 1) || (j == 2)) {

                   flash_info[i].start[j] =

                       flashbase + 0x4000 + (j -

                                     1) *

                       0x2000;

                }

 

                /* 4th 32 KB */

                if (j == 3) {

                   flash_info[i].start[j] =

                       flashbase + 0x8000;

                }

            } else {

                flash_info[i].start[j] =

                   flashbase + (j - 3) * MAIN_SECT_SIZE;

            }

        }

        size += flash_info[i].size;

    }

 

    //flash上保存有RO, RW的地方进行保护,monitor_flash_len RO + RW的长度

    flash_protect (FLAG_PROTECT_SET,

               CFG_FLASH_BASE,

               CFG_FLASH_BASE + monitor_flash_len - 1,

               &flash_info[0]);

 

    //flash上保存有环境变量的地方进行保护

    flash_protect (FLAG_PROTECT_SET,

               CFG_ENV_ADDR,

               CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);

 

    return size;

}

  该函数就是记录下flash的大小,数量,sector的大小数量等,并对flash上重要的数据进行保护。

 

继续看display_flash_config()

lib_arm/board.c:

static void display_flash_config (ulong size)

{

    puts ("Flash: ");

    print_size (size, "/n");

}

很简单,打印flash的大小信息。

 

继续看start_armboot()接下来要初始化的东西:

lib_arm/Board.c:

void start_armboot (void)

{

    ……

    /* armboot_start is defined in the board-specific linker script */

    mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

 

#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 */

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

 

    /* 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) {

            gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;

            if (s)

                s = (*e) ? e + 1 : e;

        }

    }

 

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

 

    jumptable_init ();

 

    console_init_r (); /* fully init console as a device */

   ……

}

接着看mem_malloc_init()

lib_arm/board.c:

/*

 * Begin and End of memory area for malloc(), and current "brk"

 */

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

}

这个函数就是保存malloc区域的起始地址,结束地址,并清0这块区域, 这块区域在RAM中的具体位置可查看上面的图。

 

接着看env_relocate

common/env_common.c:

void env_relocate (void)

{

    DECLARE_GLOBAL_DATA_PTR; /*定义一个gd_t对象指向ram中的gd_t区域*/

 

    DEBUGF ("%s[%d] offset = 0x%lx/n", __FUNCTION__,__LINE__,

        gd->reloc_off);

 

#ifdef CONFIG_AMIGAONEG3SE

    enable_nvram();

#endif

 

/*env_ptr指向存放环境变量的区域*/

#ifdef ENV_IS_EMBEDDED

    /*

     * The environment buffer is embedded with the text segment,

     * just relocate the environment pointer

     */

    env_ptr = (env_t *)((ulong)env_ptr + gd->reloc_off);

    DEBUGF ("%s[%d] embedded ENV at %p/n", __FUNCTION__,__LINE__,env_ptr);

#else

    /*

     * We must allocate a buffer for the environment

     */

    env_ptr = (env_t *)malloc (CFG_ENV_SIZE);

    DEBUGF ("%s[%d] malloced ENV at %p/n", __FUNCTION__,__LINE__,env_ptr);

#endif

 

    /*

     * After relocation to RAM, we can always use the "memory" functions

     */

    env_get_char = env_get_char_memory;

 

/*

* 如果在env_init中没有初始化合适的环境变量则使用默认的环境变量来作为环境变量值

* 否则使用env_init中定义好的环境变量值

*/

    if (gd->env_valid == 0) {

#if defined(CONFIG_GTH) || defined(CFG_ENV_IS_NOWHERE) /* Environment not changable */

        puts ("Using default environment/n/n");

#else

        puts ("*** Warning - bad CRC, using default environment/n/n");

        SHOW_BOOT_PROGRESS (-1);

#endif

 

        if (sizeof(default_environment) > ENV_SIZE)

        {

            puts ("*** Error - default environment is too large/n/n");

            return;

        }

 

        memset (env_ptr, 0, sizeof(env_t));

        memcpy (env_ptr->data,

            default_environment,

            sizeof(default_environment));  /*把默认值存入RAM相应区域*/

#ifdef CFG_REDUNDAND_ENVIRONMENT

        env_ptr->flags = 0xFF;

#endif

        env_crc_update ();  /*更新crc校验值*/

        gd->env_valid = 1;  /*标记环境变量有效*/

    }

    else {

        env_relocate_spec ();

    }

    gd->env_addr = (ulong)&(env_ptr->data);

 

#ifdef CONFIG_AMIGAONEG3SE

    disable_nvram();

#endif

}

该函数重新分配了一块区域用于存放环境变量,并在gd_t区域保存了这个地址值。

 

接着看devices_init:

common/Devices.c:

int devices_init (void)

{

#ifndef CONFIG_ARM     /* already relocated for current ARM implementation */

    DECLARE_GLOBAL_DATA_PTR;

 

    ulong relocation_offset = gd->reloc_off;

    int i;

 

    /* relocate device name pointers */

    for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {

        stdio_names[i] = (char *) (((ulong) stdio_names[i]) +

                       relocation_offset);

    }

#endif

 

    /* Initialize the list */

    /*创建一个保存device的列表*/

    devlist = ListCreate (sizeof (device_t));  

 

    if (devlist == NULL) {

        eputs ("Cannot initialize the list of devices!/n");

        return -1;

    }

#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)

    i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);

#endif

#ifdef CONFIG_LCD

    drv_lcd_init ();

#endif

#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)

    drv_video_init ();

#endif

#ifdef CONFIG_KEYBOARD

    drv_keyboard_init ();

#endif

#ifdef CONFIG_LOGBUFFER

    drv_logbuff_init ();

#endif

    drv_system_init ();

#ifdef CONFIG_SERIAL_MULTI

    serial_devices_init ();

#endif

#ifdef CONFIG_USB_TTY

    drv_usbtty_init ();

#endif

#ifdef CONFIG_NETCONSOLE

    drv_nc_init ();

#endif

 

    return (0);

}

这个函数实际上就是根据板子的配置初始化各种设备,并调用device_register()注册到系统中去,这里我们以drv_system_init为例解释一下,其他代码类似。

 

common/Devices.c:

/**************************************************************************

 * SYSTEM DRIVERS

 **************************************************************************

 */

 

static void drv_system_init (void)

{

    device_t dev;

 

    memset (&dev, 0, sizeof (dev));

 

    strcpy (dev.name, "serial"); /*串口设备*/

    dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; /*设备属性*/

    /*注册设备操作函数集(输入函数,输出函数等)*/

#ifdef CONFIG_SERIAL_SOFTWARE_FIFO

    dev.putc = serial_buffered_putc;

    dev.puts = serial_buffered_puts;

    dev.getc = serial_buffered_getc;

    dev.tstc = serial_buffered_tstc;

#else

    dev.putc = serial_putc;

    dev.puts = serial_puts;

    dev.getc = serial_getc;

    dev.tstc = serial_tstc;

#endif

 

/*把该设备注册进系统中去,即把dev添加进上面创建的设备列表中去*/

    device_register (&dev);     

 

    /*注册一个空设备*/

#ifdef CFG_DEVICE_NULLDEV

    memset (&dev, 0, sizeof (dev));

 

    strcpy (dev.name, "nulldev");

    dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;

    dev.putc = nulldev_putc;

    dev.puts = nulldev_puts;

    dev.getc = nulldev_input;

    dev.tstc = nulldev_input;

 

    device_register (&dev);

#endif

}

该函数注册了一个串口设备和一个空设备(根据配置而定)。其他的设备初始化函数以此大同小异,主要就是初始化好相关设备的设备信息,并注册到系统中去,详细代码大家可以自己去分析。

 

接下来看jumptable_init

common/exports.c:

void jumptable_init (void)

{

    DECLARE_GLOBAL_DATA_PTR;  /*这个还用说吗?*/

    int i;

 

    /*分配一块buffer用于存放跳转函数地址*/

    gd->jt = (void **) malloc (XF_MAX * sizeof (void *));

    for (i = 0; i < XF_MAX; i++)

        gd->jt[i] = (void *) dummy;/*默认跳转函数地址*/

 

    /*为每种功能定义各自的跳转函数*/

    gd->jt[XF_get_version] = (void *) get_version;

    gd->jt[XF_malloc] = (void *) malloc;

    gd->jt[XF_free] = (void *) free;

    gd->jt[XF_get_timer] = (void *)get_timer;

    gd->jt[XF_udelay] = (void *)udelay;

#if defined(CONFIG_I386) || defined(CONFIG_PPC)

    gd->jt[XF_install_hdlr] = (void *) irq_install_handler;

    gd->jt[XF_free_hdlr] = (void *) irq_free_handler;

#endif  /* I386 || PPC */

#if (CONFIG_COMMANDS & CFG_CMD_I2C)

    gd->jt[XF_i2c_write] = (void *) i2c_write;

    gd->jt[XF_i2c_read] = (void *) i2c_read;

#endif  /* CFG_CMD_I2C */

}

  可以看出该函数主要就是为不同的功能安装了不同的功能函数。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值