kernel hooks The Kernel Hooks Interface is a generalised facility for placing hooks in arbitrary kernel locations.
A hook is a location in the kernel that calls out of the kernel to a kernel module routine - a hook exit routine. It enables many kernel enhancements, which are otherwise self-contained, to become loadable kernel modules and retain a substantial degree of independence from the kernel source.
Hooks are implemented as fast and slim-line insertions to kernel space code. When not active that have practically no overhead to the kernel.
LK init hook 在lk/top下除了main.c文件外还有一个init.c,实现了init hook功能。下面解析一下代码。
mian.c 在lk_main()中的函数有(按顺序排):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 //在thread_init_early()和arch_early_init()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_ARCH_EARLY - 1); //在arch_early_init()和platform_early_init()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH_EARLY, LK_INIT_LEVEL_PLATFORM_EARLY - 1); //在platform_early_init()和target_early_init()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM_EARLY, LK_INIT_LEVEL_TARGET_EARLY - 1); //在target_early_init()和heap_init()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET_EARLY, LK_INIT_LEVEL_HEAP - 1); //在heap_init()和kernel_init()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_HEAP, LK_INIT_LEVEL_KERNEL - 1); //在kernel_init()和thread_create()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_KERNEL, LK_INIT_LEVEL_THREADING - 1);
在bootstrap2()中的函数有(按顺序排):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 //在bootstrap2()函数刚进来,arch_init()之前: lk_primary_cpu_init_level(LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_ARCH - 1); //在arch_init()和platform_init()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_ARCH, LK_INIT_LEVEL_PLATFORM - 1); //在platform_init()和target_init()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_PLATFORM, LK_INIT_LEVEL_TARGET - 1); //在target_init()和apps_init()之间: lk_primary_cpu_init_level(LK_INIT_LEVEL_TARGET, LK_INIT_LEVEL_APPS - 1); //在apps_init()之后 lk_primary_cpu_init_level(LK_INIT_LEVEL_APPS, LK_INIT_LEVEL_LAST);
在lk_init_secondary_cpus()中的函数有(按顺序排):
1 lk_init_level(LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_LEVEL_THREADING, LK_INIT_LEVEL_LAST);
init.h 定义的枚举在init.h中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 enum lk_init_level { LK_INIT_LEVEL_EARLIEST = 1, LK_INIT_LEVEL_ARCH_EARLY = 0x10000, LK_INIT_LEVEL_PLATFORM_EARLY = 0x20000, LK_INIT_LEVEL_TARGET_EARLY = 0x30000, LK_INIT_LEVEL_HEAP = 0x40000, LK_INIT_LEVEL_VM = 0x50000, LK_INIT_LEVEL_KERNEL = 0x60000, LK_INIT_LEVEL_THREADING = 0x70000, LK_INIT_LEVEL_ARCH = 0x80000, LK_INIT_LEVEL_PLATFORM = 0x90000, LK_INIT_LEVEL_TARGET = 0xa0000, LK_INIT_LEVEL_APPS = 0xb0000, LK_INIT_LEVEL_LAST = UINT_MAX, }; enum lk_init_flags { LK_INIT_FLAG_PRIMARY_CPU = 0x1, LK_INIT_FLAG_SECONDARY_CPUS = 0x2, LK_INIT_FLAG_ALL_CPUS = LK_INIT_FLAG_PRIMARY_CPU | LK_INIT_FLAG_SECONDARY_CPUS, LK_INIT_FLAG_CPU_SUSPEND = 0x4, LK_INIT_FLAG_CPU_RESUME = 0x8, };
lk_primary_cpu_init_level等函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 typedef void (*lk_init_hook)(uint level); //函数类型的typedef,在下面的struct中用到,该函数接收一个uint类型的level参数,返回为空(void)。 void lk_init_level(enum lk_init_flags flags, uint start_level, uint stop_level); static inline void lk_primary_cpu_init_level(uint start_level, uint stop_level) { lk_init_level(LK_INIT_FLAG_PRIMARY_CPU, start_level, stop_level); } // 指定lk_init_flags flags为LK_INIT_FLAG_PRIMARY_CPU static inline void lk_init_level_all(enum lk_init_flags flags) { lk_init_level(flags, LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_LAST); } //init_level包含整个区间 struct lk_init_struct { uint level; //init level uint flags; // lk_init_flags flags lk_init_hook hook; //指向的函数 const char *name; //hook name }; #define LK_INIT_HOOK_FLAGS(_name, _hook, _level, _flags) \ const struct lk_init_struct _init_struct_##_name __ALIGNED(sizeof(void *)) __SECTION(".lk_init") = { \ .level = _level, \ .flags = _flags, \ .hook = _hook, \ .name = #_name, \ }; //该宏声明一个const型的lk_init_struct并对其进行初始化,宏传入4个参数(_name, _hook, _level, _flags) //lk_init_struct 的名字为_init_struct_+'_name' //_init_struct_+'_name'.level = _level //_init_struct_+'_name'.flags = _flags //_init_struct_+'_name'.hook = _hook //_init_struct_+'_name'.name = '_name' #define LK_INIT_HOOK(_name, _hook, _level) \ LK_INIT_HOOK_FLAGS(_name, _hook, _level, LK_INIT_FLAG_PRIMARY_CPU) //该宏将LK_INIT_HOOK_FLAGS中的_flags定为LK_INIT_FLAG_PRIMARY_CPU
通过 __ALIGNED(sizeof(void *)) __SECTION(“.lk_init”)在编译器编译时,将各个地方LK_INIT_HOOK声明的lk_init_struct加入到.lk_init的数据段中。
__SECTION(“name”)是gcc编译器支持的一个编译特性(arm编译器也支持此特性),实现在编译时把某个函数/数据放到name的数据段中。
init.c lk_init_level()函数在init.c中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 注意两个外部声明: extern const struct lk_init_struct __lk_init[]; extern const struct lk_init_struct __lk_init_end[]; void lk_init_level(enum lk_init_flags required_flag, uint start_level, uint stop_level) { LTRACEF("flags %#x, start_level %#x, stop_level %#x\n", required_flag, start_level, stop_level); ASSERT(start_level > 0); uint last_called_level = start_level - 1; const struct lk_init_struct *last = NULL; for (;;) { /* search for the lowest uncalled hook to call */ LTRACEF("last %p, last_called_level %#x\n", last, last_called_level); const struct lk_init_struct *found = NULL; bool seen_last = false; for (const struct lk_init_struct *ptr = __lk_init; ptr != __lk_init_end; ptr++) { LTRACEF("looking at %p (%s) level %#x, flags %#x, seen_last %d\n", ptr, ptr->name, ptr->level, ptr->flags, seen_last); if (ptr == last) seen_last = true; /* reject the easy ones */ if (!(ptr->flags & required_flag)) continue; if (ptr->level > stop_level) continue; if (ptr->level < last_called_level) continue; if (found && found->level <= ptr->level) continue; /* keep the lowest one we haven't called yet */ if (ptr->level >= start_level && ptr->level > last_called_level) { found = ptr; continue; } /* if we're at the same level as the last one we called and we've * already passed over it this time around, we can mark this one * and early terminate the loop. */ if (ptr->level == last_called_level && ptr != last && seen_last) { found = ptr; break; } } if (!found) break; #if TRACE_INIT if (found->level >= EARLIEST_TRACE_LEVEL) { printf("INIT: cpu %d, calling hook %p (%s) at level %#x, flags %#x\n", arch_curr_cpu_num(), found->hook, found->name, found->level, found->flags); } #endif found->hook(found->level); last_called_level = found->level; last = found; } }
lk_init_level()中主要为一个循环,从__lk_init到__lk_init_end之间遍历,找到符合条件的init hook去执行。
__lk_init 和 __lk_init_end 是 .lk_init数据段中定义的起始和结束,定义在lk/top/init.ld文件中:
1 2 3 4 5 6 7 8 SECTIONS { .lk_init : { __lk_init = .; KEEP (*(.lk_init)) __lk_init_end = .; } } INSERT AFTER .rodata;
使用init hook 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void test_hook(uint level) { LTRACEF("level %#x\n", level); } LK_INIT_HOOK(test, test_hook, 1); static void dpc_init(uint level) { event_init(&dpc_event, false, 0); thread_detach_and_resume(thread_create("dpc", &dpc_thread_routine, NULL, DPC_PRIORITY, DEFAULT_STACK_SIZE)); } LK_INIT_HOOK(libdpc, &dpc_init, LK_INIT_LEVEL_THREADING); //lk中dpc thread就是以init hook的方式,在bootstrap2(void *arg)函数的开头创建的。
NOTE: 1.在编译好的lk.elf里查找.lk_init
1 aarch64-elf-readelf build-path/lk.elf -x .lk_init
2.查看一些debug信息
1 vim build-path/lk.elf.debug.lst
3.查看system-onesegment信息
1 vim build-path/system-onesegment.ld
本文标题: Little Kernel 05
文章作者: Mr Bluyee
发布时间: 2018-11-15
最后更新: 2019-07-15
原始链接: https://www.mrbluyee.com/2018/11/15/Little-Kernel-05/
版权声明: The author owns the copyright, please indicate the source reproduced.