linux内核C阶段分析(一)
今天开始就进入C语言阶段了
Asmlinkage
#define asmlinkage CPP_ASMLINKAGE
#ifdef __cplusplus
#define CPP_ASMLINKAGE extern "C"
#else
#define CPP_ASMLINKAGE
#endif
还有一种说法是
#define asmlinkage __attribute__((regparm(0))) 作用是不使用寄存器传递参数,强制让参数走堆栈
__init
kernel-3.4.39\include\linux\init.h
#define __init __section(.init.text) __cold notrace
用于告诉编译器相关函数或变量仅用于初始化。
编译器将标__init的所有代码存在特殊的内存段中,初始化结束后就释放这段内存。
lockdep_init();
kernel-3.4.39\include\linux\lockdep.h
# define lockdep_init() do { } while (0)
检测死锁模块
smp_setup_processor_id(); 判断内核运行在那个物理核心上
kernel-3.4.39\arch\arm\kernel\setup.c
debug_objects_early_init();
kernel-3.4.39\include\linux\debugobjects.h
static inline void debug_objects_early_init(void) { }
在早期引导期间调用,以初始化散列并将静态对象池对象链接到轮询列表中。
这个调用之后,对象跟踪器就完全可以运行了。这个模块是个通用的调试框架,用来跟踪object的生命周期。
使用这个宏打开和关闭这个功能 CONFIG_DEBUG_OBJECTS
如果开启了这个功能会该函数的作用就是初始化obj_hash(hash锁)、obj_static_pool(静态对象池)这两个全局变量
boot_init_stack_canary();
\kernel-3.4.39\include\linux\stackprotector.h
static inline void boot_init_stack_canary(void)
{
}
通过宏CONFIG_CC_STACKPROTECTOR控制打开和关闭
该函数主要用于初始化“金丝雀“——canary的值。
用于防止栈溢出攻击。
通常採用两种方法防止栈缓冲溢出:
1 发生栈缓冲溢出时将其检測出来。从而阻止通过恶意代码更改指令指针;
2 未直接检測栈缓冲溢出的情况下,预防恶意代码攻击。
stack canary技术属于第一中方法的一种。在恶意代码运行前,可以发现栈缓冲溢出。
cgroup_init_early();
kernel-3.4.39\kernel\cgroup.c
cgroup_init_early—在系统启动时初始化cgroup
在系统启动时初始化cgroup,并初始化任何早期初始化请求的子系统。
cgroup就是control group,就是将一个或者多个task组成一个group,cgroup对这个group的资源进行控制。具体实现依赖于具体的cgroup sub system的实现。
为啥要开发cgroup呢? 打个比方你们组的成员公用一台服务器,现在某个人需要编译代码“make -j 20",然后服务器开始编译代码,其余人的体验就变差,变得很卡,影响工作。
你这时候就会想是不是可以给每个人分配一个最大资源的限制,这样一个人编译代码不会影响到别人的工作。cgroup就是这个用途。
local_irq_disable();
功能是屏蔽当前CPU上的所有中断
early_boot_irqs_disabled = true;
通过一个静态全局变量 early_boot_irqs_enabled来帮助我们调试代码,通过这个标记可以帮助我们知道是否在”early bootup code”,也可以通过这个标志警告是有无效的终端打开。
tick_init();
kernel-3.4.39\kernel\time\tick-common.c
void __init tick_init(void)
{
clockevents_register_notifier(&tick_notifier);
}
内核通知链机制初始化tick控件
用clockevents框架注册通知程序
boot_cpu_init();
kernel-3.4.39\init\main.c
对于CPU核的系统来说,设置第一个CPU核为活跃
page_address_init();
kernel-3.4.39\mm\highmem.c
初始化内存页链表的地址
printk(KERN_NOTICE "%s", linux_banner);
kernel-3.4.39\init\version.c
const char linux_banner[] =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
打印linux_banner的信息
setup_arch(&command_line);
kernel-3.4.39\arch\arm\kernel\setup.c
start_kernel阶段最重要的一个函数
内存初始化
mm_init_owner(&init_mm, &init_task);
kernel-3.4.39\kernel\fork.c
void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
{
mm->owner = p;
}
通过宏CONFIG_MM_OWNER控制
全部任务都具有自己的内存,启动阶段中的当前任务必须具备属于自己的内存。
mm_init_cpumask(&init_mm);
kernel-3.4.39\include\linux\mm_types.h
static inline void mm_init_cpumask(struct mm_struct *mm)
{
#ifdef CONFIG_CPUMASK_OFFSTACK
mm->cpu_vm_mask_var = &mm->cpumask_allocation;
#endif
}
通过宏CONFIG_CPUMASK_OFFSTACK控制
当CONFIG_CPUMASK_OFFSTACK=y时cpumasks不再放在堆栈上。
当CONFIG_CPUMASK_OFFSTACK=n时cpumask_var_t为struct cpumask[1](而且alloc_cpumask_var等为空操作)。
setup_command_line(command_line); 初始化命令行
kernel-3.4.39\init\main.c
我们需要存储未触及的命令行,以备将来参考。
我们还需要存储触摸命令行,因为参数解析是在适当的位置执行的,我们应该允许组件存储名称/值的引用,以供将来引用。
setup_nr_cpu_ids();
kernel-3.4.39\init\main.c
void __init setup_nr_cpu_ids(void)
{
nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
}
先到这里,吃饭去喽~