BitTigerio 2018-01-09
uboot版本:uboot-201711
要分析uclass之前,首先得搞清楚两个宏U_BOOT_DRIVER及U_BOOT_DEVICE的作用:
1.U_BOOT_DRIVER及U_BOOT_DEVICE宏定义如下:
1 #define U_BOOT_DRIVER(__name) \ 2 ll_entry_declare(struct driver, __name, driver) 3 4 #define U_BOOT_DEVICE(__name) \ 5 ll_entry_declare(struct driver_info, __name, driver_info) 6 7 #define ll_entry_declare(_type, _name, _list) \ 8 _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \ 9 __attribute__((unused, \ 10 section(".u_boot_list_2_"#_list"_2_"#_name)))
下面具体分析如下:
例如:
U_BOOT_DRIVER(serial_s5p) = { .name = "serial_s5p", .id = UCLASS_SERIAL, .of_match = s5p_serial_ids, .ofdata_to_platdata = s5p_serial_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata), .probe = s5p_serial_probe, .ops = &s5p_serial_ops, .flags = DM_FLAG_PRE_RELOC, };
根据上述宏定义展开得到:
ll_entry_declare(struct driver, serial_s5p, driver) struct driver _u_boot_list_2_driver_2_serial_s5p __aligned() __attribute__((unused, section(".u_boot_list_2_driver_2_serial_s5p"))) = { .name = "serial_s5p", .id = UCLASS_SERIAL, .of_match = s5p_serial_ids, .ofdata_to_platdata = s5p_serial_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata), .probe = s5p_serial_probe, .ops = &s5p_serial_ops, .flags = DM_FLAG_PRE_RELOC, };
从上面我们可以看到声明他们的时候对它们做了如下要求:
1.要求它们存放的时候4字节对齐,这通常是为了更方便的访问处理它们;
2.要求它们存放在一个各自独有的段里面
在链接脚本arch/arm/cpu/u-boot.lds中有如下定义:
. = ALIGN(); .u_boot_list : { KEEP(*(SORT(.u_boot_list*))); }
所有以.u_boot_list开头的段多将在这里存放,KEEP关键字是为了保证所有的段多被加进来,不要被链接器自作聪明的把某些它认为没有的段舍弃;
用宏U_BOOT_DRIVER和U_BOOT_DEVICE声明的变量将被分配到自己一个特有的段下,在链接的时候被组织到一起,具体可以在uboot编译成功后生成的u-boot.map中查看到u_boot_list段的相关信息如下:
注意到u_boot_list_2_driver_1和u_boot_list_2_driver_3,这段地址范围内即为驱动函数列表集合
搞清楚这两个关键宏后下篇将具体分析uclass,uclass_driver,udevice,driver之间的关系