从零移植uboot 2017 到nuc970(第十五天)

来源:互联网 发布:淘宝真丝针织背心 编辑:程序博客网 时间:2024/05/28 23:23

  最近事情比较多,有其他的事情一直打扰,终于抽空进展了一点。 继续昨天的,首先

CONFIG_SPL_STACK_R is defined, then at this point the stack and global_data are relocated to belowCONFIG_SPL_STACK_R_ADDR. For non-SPL, U-Boot is relocated to run at the top of memory. ulong spl_relocate_stack_gd(void)

  这个函数的comment,里面有重要的一句话This is typically because we need * more stack space for things like the

MMC sub-system.

  而我们的头文件默认没有定义CONFIG_SPL_STACK_R,所以不用管他。而接下来的CONFIG_USE_ARCH_MEMSET,

我没有在任何地方找到它的解释,但是实际上反汇编里面已经有这个函数,看来是默认带有的配置项,且自动包含或者现

在隐约能理解一些以前不能理解的东西。

 memset * memset - Fill a region of memory with the given value * @s: Pointer to the start of the area. * @c: The byte to fill the area with * @count: The size of the area.ro: _bss_start r1 :_bss_end r2: _bss_len

  链接时确定地址,具体先不深究。下面就是清零bss段,在调用spl阶段最重要的b_i_f之前:

    /* call board_init_r(gd_t *id, ulongdest_addr) */    mov     r0, r9                  /* gd_t */    ldr    r1, [r9, #GD_RELOCADDR]    /* dest_addr */    /* call board_init_r */

  有必要深究下 r0,r1的值此时为多少。r9 此时为gd_t的指针,而实际上gd的数据此时都是0所以 r1=r0的值。接下来就是重头

戏了,虽然以前分析过,但是我还是会再分析一遍,到现在都不需要修改什么。

void board_init_r(gd_t *dummy1, ulong dummy2){    u32 spl_boot_list[] = {        BOOT_DEVICE_NONE,        BOOT_DEVICE_NONE,        BOOT_DEVICE_NONE,        BOOT_DEVICE_NONE,        BOOT_DEVICE_NONE,    };    struct spl_image_info spl_image;    debug(">>spl:board_init_r()\n");#if defined(CONFIG_SYS_SPL_MALLOC_START)    mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,            CONFIG_SYS_SPL_MALLOC_SIZE);    gd->flags |= GD_FLG_FULL_MALLOC_INIT;#endif
  这里我使用简单功能版的malloc:
  if (!(gd->flags & GD_FLG_SPL_INIT)) {        if (spl_init())            hang();    }

   这个要分析下,首先gd-flags应该是0值,然后这个语句是相当于判断是否是第一次执行吧,在spl_init()中最后找到

gd->flags |= GD_FLG_SPL_INIT;说明我的想法是对的关于具体的功能可能需要点关于设备树的知识了。

 memset(&spl_image, '\0', sizeof(spl_image));    //用零填充了spl_image结构体    board_boot_order(spl_boot_list);    //这个以前解析过,我直接赋值boot_from_nand    if (boot_from_devices(&spl_image, spl_boot_list,                  ARRAY_SIZE(spl_boot_list))) {        puts("SPL: failed to boot from all boot devices\n");        hang();    }    switch (spl_image.os) {    case IH_OS_U_BOOT:        debug("Jumping to U-Boot\n");        break;    default:        debug("Unsupported OS image.. Jumping nevertheless..\n");    debug("loaded - jumping to U-Boot...\n");    spl_board_prepare_for_boot();//这个以前解析过什么都没有做    jump_to_image_no_args(&spl_image);    }struct spl_image_info {    const char *name;    u8 os;    ulong load_addr;    ulong entry_point;    u32 size;    u32 flags;};
  // 最后两个重要的函数boot_from_devices,jump_to_image_no_args
/** * boot_from_devices() - Try loading an booting U-Boot from a list of devices * * @spl_image: Place to put the image details if successful * @spl_boot_list: List of boot devices to try * @count: Number of elements in spl_boot_list * @return 0 if OK, -ve on error */
  里面又有个重要的函数spl_ll_find_loader 宏函数,以前解析过,现在该函数里面:
struct spl_image_loader *drv =        ll_entry_start(struct spl_image_loader, spl_image_loader);
  #define ll_entry_start(_type, _list)                    \({                                    \    static char start[0] __aligned(4) __attribute__((unused,    \        section(".u_boot_list_2_"#_list"_1")));            \    (_type *)&start;                        \})
struct spl_image_loader, spl_image_loader,实际拓展开 为
struct spl_image_loader *drv = ({             static char start[0] __aligned(4) __attribute__((unused,section(".u_boot_list_2_spl_image_loader_1")));        (struct spl_image_loader*)&start;                                              })

  这种用法不太常见,不太清楚会以什么样的作用机制,这里标记下。实际上这部分非常多,但是很感兴趣,spl的最核心

的地方就是这里的实现了。

  一点一点看吧,在common/spl/spl_nand.c中有:
 SPL_LOAD_IMAGE_METHOD("NAND", 1, BOOT_DEVICE_NAND, spl_nand_load_image);/* * _priority is the priority of this method, 0 meaning it will be the top * choice for this device, 9 meaning it is the bottom choice. * _boot_device is the BOOT_DEVICE_... value * _method is the load_image function to call 这句话很关键 */#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT#define SPL_LOAD_IMAGE_METHOD(_name, _priority, _boot_device, _method) \    SPL_LOAD_IMAGE(_method ## _priority ## _boot_device) = { \        .name = _name, \        .boot_device = _boot_device, \        .load_image = _method, \    }#define SPL_LOAD_IMAGE(__name)                    \    ll_entry_declare(struct spl_image_loader, __name, spl_image_loader)#define ll_entry_declare(_type, _name, _list)                \    _type _u_boot_list_2_##_list##_2_##_name __aligned(4)        \            __attribute__((unused,                \            section(".u_boot_list_2_"#_list"_2_"#_name)))
  拓展开来
SPL_LOAD_IMAGE(spl_nand_load_image_1_BOOT_DEVICE_NAND) = { \        .name = "NAND", \        .boot_device = BOOT_DEVICE_NAND, \        .load_image = spl_nand_load_image, \    }

  接着

ll_entry_declare(struct spl_image_loader, spl_nand_load_image_1_BOOT_DEVICE_NAND, spl_image_loader)= { \    .name = "NAND", \        .boot_device = BOOT_DEVICE_NAND, \        .load_image = spl_nand_load_image, \    }

  接着 

   

struct spl_image_loader _u_boot_list_2_spl_image_loader_2_spl_nand_load_image_1_BOOT_DEVICE_NAND \   __aligned(4) __attribute__((unused,section(".u_boot_list_2_spl_image_loader_2_spl_nand_load_image_1_BOOT_DEVICE_NAND")))   ={ \        .name = "NAND", \        .boot_device = BOOT_DEVICE_NAND, \        .load_image = spl_nand_load_image, \ //就是该文件里面的函数了 也就是以前提问的,到底是哪个函数加载了uboot的主体镜像    }

  我也是第一次见这么长的声明,今天到这里:补充两个知识:

    __attribute__((unused)) unused:This attribute, attached to a function, means that the function is meant to be

 possibly unused. GCC will not produce a warning for this function.

    __attribute__((section("section_name"))) 其作用是将作用的函数或数据放入指定名为"section_name"的段。具体请参考

https://my.oschina.net/u/180497/blog/177206 感谢这位前辈的总结,写的非常好。还需要再回顾下内联函数,和宏的知识,有点忘了

    
    
 
1 0
原创粉丝点击