项目背景
WiFi模块rlt8812au 替换成rlt8812cu,支持rlt8812cu驱动且保持兼容原有模块
驱动移植
根据厂家提供的驱动包,修改makefile和Kconfig文件,根据需要修改部分源码,完成驱动移植。移植验证ok之后,rlt8812cu驱动生效。现在考虑兼容问题:
1、将两个模块均静态编译进内核。编译时发现报错,提示很多函数重复定义,显然该方法不可行。
2、将两个WiFi驱动模块均动态编译。这种方法需要业务将两个模块都加载即可,(不会因为是一家厂两份驱动包含了很多同名的函数而造成模块的驱动加载失败,每一个驱动模块加载,系统会准备一块地址空间,将该ko映射到该空间,所以每一个ko(或者静态加载到内核的驱动所包含的函数)对用的地址是不一样的,他会根据地址来查找对应的函数,后面详细表述见验证部分)
3、将之前的模块加载的WiFi驱动保留,将另一种驱动静态包含到内核当中。这样当新模块使用时直接使用内核当中的驱动,使用老wifi模块时调用ko,也不会出现相同函数错乱调用的情况,原理一样:根据地址来查找对应的函数。这样只修改小系统即可,业务不做改动。
验证
# cat /proc/kallsyms 分别查看新模块驱动静态加载到内核与新模块静态加载到内核并且老模块动态加载的kallsyms 文件。
1)新模块驱动静态加载到内核与新模块静态加载到内核并且老模块动态加载对比发现:新模块静态加载到内核所调用的函数地址是一样的。新模块驱动静态加载到内核与新模块静态加载到内核并且老模块动态加载函数对比,动态加载的函数虽然和静态调用 的函数名相同,但是调用的时动态加载的函数。
总结
基于以上验证加载同一厂家不同模块大胆去做吧,除了两个模块都包含到内核编译出现函数多次定义之外,不要因为有相同的函数名而造成调用错乱问题而担忧。
补充知识(参考文章如下)
https://www.xuebuyuan.com/598359.html
在内核中通过/proc/kallsyms获得符号的地址
Linux内核符号表/proc/kallsyms的形成过程 ---------------------------------------------------------------------------
./scripts/kallsyms.c负责生成System.map ./kernel/kallsyms.c负责生成/proc/kallsyms
./scripts/kallsyms.c解析vmlinux(.tmp_vmlinux)生成kallsyms.S(.tmp_kallsyms.S),然后内核编译过程中将kallsyms.S(内核符号表)编入内核镜像uImage
内核启动后./kernel/kallsyms.c解析uImage形成/proc/kallsyms
/proc/kallsyms包含了内核中的函数符号(包括没有EXPORT_SYMBOL)、全局变量(用EXPORT_SYMBOL导出的全局变量)
如何将内核中的函数、全局变量、静态变量都导出到/proc/kallsyms ------------------------------------------------------------------------ ./scripts/kallsyms
static int all_symbols = 0; ==> static int all_symbols = 1;
引入kallsyms ------------------------------------------------------------------------ 在2.6内核中,为了更好地调试内核,引入了kallsyms。kallsyms抽取了内核用到的所有函数地址(全局的、静态的)和非栈数据变量地址,生成一个数据块,作为只读数据链接进kernel image,相当于内核中存了一个System.map。需要配置CONFIG_KALLSYMS
.config CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y 符号表中包括所有的变量(包括没有用EXPORT_SYMBOL导出的变量) CONFIG_KALLSYMS_EXTRA_PASS=y
make menuconfig General setup ---> [*] Configure standard kernel features (for small systems) ---> [*] Load all symbols for debugging/ksymoops [*] Include all symbols in kallsyms [*] Do an extra kallsyms pass
注: 配置CONFIG_KALLSYMS_ALL之后,就不需要修改all_symbol静态变量为1了
|--------------------| | | | | ~ ~ | | | | 0xc05d 1dc0 |--------------------| _end | | | | | BSS | | | | | 0xc05a 4500 |--------------------| __bss_start | | 0xc05a 44e8 |--------------------| _edata | | | | | DATA | | | | | 0xc058 2000 |--------------------| __data_start init_thread_union | | 0xc058 1000 _etext |--------------------| | | | rodata | | | 0xc056 d000 |--------------------| __start_rodata | | | | | Real text | | | | | 0xc02a 6000 TEXT |--------------------| _text __init_end | | | Exit code and data | DISCARD 这个section在内核完成初始化后 | | 会被释放掉 0xc002 30d4 |--------------------| _einittext | | | Init code and data | | | 0xc000 8000 _stext |--------------------|<------------ __init_begin | | 0xc000 0000 |--------------------|
arch/arm/kernel/vmlinux.lds.S
注: 1. 文本段中的只读段均为变量 2. 文本段中的INIT断,可视为变量,因为命令中不会调用初始化函数,另外该区域在内核启动完成后,已经被bootmem释放了,所以该区域可能会被另作它用 3. T The symbol is in the text(code) section D The symbol is in the initialized data section R The sysbol is in a read only data section t static d static R const r static const
转存失败重新上传取消