环境
U-Boot版本:官方2023.04
开发板:ZYNQ 7000 ZC702Kit Rev1.1
注册代码宏定义
/* Declare a new uclass_driver */
#define UCLASS_DRIVER(__name) \
ll_entry_declare(struct uclass_driver, __name, uclass_driver)
/**
* U_BOOT_DRIVER() - Declare a new U-Boot driver
* @__name: name of the driver
*/
#define U_BOOT_DRIVER(__name) \
ll_entry_declare(struct driver, __name, driver)
/**
* ll_entry_declare() - Declare linker-generated array entry
* @_type: Data type of the entry
* @_name: Name of the entry
* @_list: name of the list. Should contain only characters allowed
* in a C variable name!
*/
#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)
ll_entry_declare 宏定义是创建一个类型为 _type 的结构体,并且存放到 _u_boot_list_2#list_2#_name 程序段。
_list 作为分类字段,保证 driver 类型连续在一起,_name作为结构体名称。
编译后 map 文件可以看到
__u_boot_list_2_uclass_driver_2_root
0x040e29f4 0x48 drivers/core/root.o
0x040e29f4 _u_boot_list_2_uclass_driver_2_root
__u_boot_list_2_uclass_driver_2_serial
0x040e2a3c 0x48 drivers/serial/serial-uclass.o
...
__u_boot_list_2_driver_2_root_driver
0x040e1ed4 0x44 drivers/core/root.o
0x040e1ed4 _u_boot_list_2_driver_2_root_driver
__u_boot_list_2_driver_2_serial_dcc
0x040e1f18 0x44 drivers/serial/arm_dcc.o
0x040e1f18 _u_boot_list_2_driver_2_serial_dcc
__u_boot_list_2_driver_2_serial_zynq
0x040e1f5c 0x44 drivers/serial/serial_zynq.o
0x040e1f5c _u_boot_list_2_driver_2_serial_zynq
__u_boot_list_2_driver_2_simple_bus
0x040e1fa0 0x44 drivers/core/simple-bus.o
0x040e1fa0 _u_boot_list_2_driver_2_simple_bus
...
设备查找
- 列表定位
#define ll_entry_start(_type, _list) \
({ \
static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
__attribute__((unused)) \
__section("__u_boot_list_2_"#_list"_1"); \
(_type *)&start; \
})
#define ll_entry_end(_type, _list) \
({ \
static char end[0] __aligned(4) __attribute__((unused)) \
__section("__u_boot_list_2_"#_list"_3"); \
(_type *)&end; \
})
设备注册时 _list 和 _name 之间加入序列 2 作为标识,每一类最前面插入一个序列为 1 并且不带 _name 的对象,最后面插入一个序列为 3 并且不带 _name 的对象。通过起始和结束的特殊对象查找一个段的地址范围。
设备数量统计
#define ll_entry_count(_type, _list) \
({ \
_type *start = ll_entry_start(_type, _list); \
_type *end = ll_entry_end(_type, _list); \
unsigned int _ll_result = end - start; \
_ll_result; \
})