编译
使用 LLVM 编译内核 (需要安装 llvm 工具链):
make mrproper
make LLVM=1 ARCH=arm defconfig
make LLVM=1 ARCH=arm Image -j12
生成 compile_commands.json:
cd scripts/clang-tools/
./gen_compile_commands.py -d ../.. # linux根目录
mv compile_commands.json ../..
NOT indexed
include <asm/xxx.h> 先找 arch/xxx/include/xxx.h,没有的话就找/include/asm-generic/xxx.h
从 dts 中获取 regs 地址并映射到 virtual address:
linux5.10: void __iomem *devm_platform_get_and_ioremap_resource(struct platform_device *pdev, unsigned int index, struct resource **res)
linux5.4: void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, unsigned int index)
相当于 platform_get_resource + devm_request_mem_region + devm_ioremap
linux 链表相关操作:
#define list_entry(ptr, type, member) \ /// list_entry作用和container_of相同
container_of(ptr, type, member)
container_of(ptr, type, member)
// ptr:表示结构体中member的地址h(已知的)
// type:表示结构体类型 struct xxx
// member:表示结构体中的成员 yyy
// 返回结构体的首地址
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor. pos中的list_head被加入了第二个成员head中
* @head: the head for your list. 要循环的链表
* @member: the name of the list_head within the struct. pos中的list_head链表对象
*/
list_for_each_entry(pos, head, member)
Initcalls
图中 initcalls 优先级从上到下。这些都是只能用于 builtin 的 modules。loadable 的 modules 使用 module_init()。
使用 initcalls 会在目标文件 object file 中创建 ELF sections。
module_init()
本质是 device_initcall。
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
kernel 的System.map
可以查看符号文件,其中__initcall6_start
后的顺序就对应device_initcall
的驱动加载顺序。
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define late_initcall(fn) __define_initcall(fn, 7)