uboot-linkerList流程

uboot中会根据情况将变量或函数放到指定的段section中,例如uboot cmd功能
这样做可以使添加的代码与uboot其他模块相对独立,例如增加一个cmd,只需要将具体操作实现,然后调用一个接口将cmd.ops放到相应段里即可。

以君正x1000e uboot为源码说明:
具体使用如下:
drivers/mtd/devices/nand_device/mxic_nand.c
1、定义flash.info,例如芯片id、容量等信息
2、实现旺宏(mxic)nand-flash芯片的读、写等接口
3、实现mxic_nand_init接口,将ops注册进nand队列中,用于启动时读取flash id后,获取对应的读写接口
4、调用SPINAND_MOUDLE_INIT(mxic_nand_init)

SPINAND_MOUDLE_INIT定义如下:

typedef int32_t (*spinand_regcall_t)(void);

#define ingenic_entry_declare(_type, _name, _list)				\
	static _type ingenic_##_list##_2_##_name __aligned(4)			\
			__attribute__((used,					\
			section(".u_boot_list_2_"#_list"_2_"#_name)))

#define SPINAND_MOUDLE_INIT(fn)      \
	ingenic_entry_declare(spinand_regcall_t, _1##fn, flash) = fn

##:以字符串连接前后两个成员,例如上面即ingenic_##list##2 ==> ingenic_flash_2
__aligned:在include/linux/compiler-gcc.h中定义,类似aligned,指定以4字节对齐
attribute:为定义的成员指定属性,即为static spinand_regcall_t ingenic_flash_2__1mxic_nand_init __aligned(4)指定属性
section:指定放到哪个段中,这里是.u_boot_list_2_flash_2__1mxic_nand_init段

综上,SPINAND_MOUDLE_INIT(mxic_nand_init)展开为:

static spinand_regcall_t ingenic_flash_2__1mxic_nand_init __aligned(4)      \
    __attribute__((used,                                                    \
    section(".u_boot_list_2_flash_2__1mxic_nand_init))) = mxic_nand_init

它定义了一个函数static spinand_regcall_t ingenic_flash_2__1mxic_nand_init,它指向mxic_nand_init

如何执行呢?
driver/mtd/devices/jz_sfc_nand.c::jz_sfc_nand_init()
jz_sfc_nand_init:
spinand_moudle_init::

 static inline int32_t spinand_moudle_init(void)
{
	spinand_regcall_t *call = ll_entry_start(spinand_regcall_t, flash);
	int ret = 0 , i, count;

	for (i = 0, count = ll_entry_count(spinand_regcall_t, flash);
		i < count;
		call++, i++) {
	    ret = (*call)();
	    if (ret) {
		printf("jz spi nand ops init func error\n");
		break;
	    }
	}
	return ret;
}

其中ll_entry_start在include/linker_lists.h中定义:

#define ll_entry_start(_type, _list)					\
({									\
	static char start[0] __aligned(4) __attribute__((unused,	\
		section(".u_boot_list_2_"#_list"_1")));			\
	(_type *)&start;						\
})

将ll_entry_start(spinand_regcall_t, flash);展开即

static char start[0] __aligned(4) __attribute__((unused,	\
    section(".u_boot_list_2_flash_1")));			\
    (_type *)&start;

这里定义了一个位于.u_boot_list_2_flash_1段的start变量,将它的地址返回
即spinand_regcall_t *call = (spinand_regcall_t *)&start;

之前将mxic_nand_init放入的是.u_boot_list_2_flash_2__1mxic_nand_init段中
为什么可以通过.u_boot_list_2_flash_1段找到mxic_nand_init呢?
这是因为编译uboot时,指定了lds,其中,不同架构有其对应的lds文件,这里用到:
./arch/mips/cpu/u-boot.lds

SECTIONS
{
    ....
    . = ALIGN(4);
    .u_boot_list : {
         KEEP(*(SORT(.u_boot_list*)));
    }
    ....        
}

lds规定了,编译时将段以什么规则去存放,这里就将段中的u_boot_list*按照大小顺序进行排列
即定义的.u_boot_list_2_flash_1,一定位于定义的.u_boot_list_2_flash_2_xxxxxx的头部

至此,流程全部结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值