start_kernel函数是内核的入口函数,定义在init/main.c文件中。我们来一个一个函数看。
asmlinkage __visible void __init start_kernel(void)
{
char *command_line;
char *after_dashes;
set_task_stack_end_magic(&init_task);//该函数定义于kernel/fork.c文件
smp_setup_processor_id();
debug_objects_early_init();
cgroup_init_early();
local_irq_disable();
early_boot_irqs_disabled = true;
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them.
*/
boot_cpu_init();
page_address_init();
pr_notice("%s", linux_banner);
setup_arch(&command_line);
/*
* Set up the the initial canary and entropy after arch
* and after adding latent and command line entropy.
*/
add_latent_entropy();
add_device_randomness(command_line, strlen(command_line));
boot_init_stack_canary();
mm_init_cpumask(&init_mm);
setup_command_line(command_line);
setup_nr_cpu_ids();
setup_per_cpu_areas();
boot_cpu_state_init();
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
build_all_zonelists(NULL);
page_alloc_init();
pr_notice("Kernel command line: %s\n", boot_command_line);
parse_early_param();
after_dashes = parse_args("Booting kernel",
static_command_line, __start___param,
__stop___param - __start___param,
-1, -1, NULL, &unknown_bootoption);
if (!IS_ERR_OR_NULL(after_dashes))
parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
NULL, set_init_arg);
jump_label_init();
/*
* These use large bootmem allocations and must precede
* kmem_cache_init()
*/
setup_log_buf(0);
vfs_caches_init_early();
sort_main_extable();
trap_init();
mm_init();
ftrace_init();
/* trace_printk can be enabled here */
early_trace_init();
/*
* Set up the scheduler prior starting any interrupts (such as the
* timer interrupt). Full topology setup happens at smp_init()
* time - but meanwhile we still have a functioning scheduler.
*/
sched_init();
/*
* Disable preemption - early bootup scheduling is extremely
* fragile until we cpu_idle() for the first time.
*/
preempt_disable();
if (WARN(!irqs_disabled(),
"Interrupts were enabled *very* early, fixing it\n"))
local_irq_disable();
radix_tree_init();
/*
* Set up housekeeping before setting up workqueues to allow the unbound
* workqueue to take non-housekeeping into account.
*/
housekeeping_init();
/*
* Allow workqueue creation and work item queueing/cancelling
* early. Work item execution depends on kthreads and starts after
* workqueue_init().
*/
workqueue_init_early();
rcu_init();
/* Trace events are available after this */
trace_init();
context_tracking_init();
/* init some links before init_ISA_irqs() */
early_irq_init();
init_IRQ();
tick_init();
rcu_init_nohz();
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
sched_clock_postinit();
printk_safe_init();
perf_event_init();
profile_init();
call_function_init();
WARN(!irqs_disabled(), "Interrupts were enabled early\n");
early_boot_irqs_disabled = false;
local_irq_enable();
kmem_cache_init_late();
/*
* HACK ALERT! This is early. We're enabling the console before
* we've done PCI setups etc, and console_init() must be aware of
* this. But we do want output early, in case something goes wrong.
*/
console_init();
if (panic_later)
panic("Too many boot %s vars at `%s'", panic_later,
panic_param);
lockdep_info();
/*
* Need to run this when irqs are enabled, because it wants
* to self-test [hard/soft]-irqs on/off lock inversion bugs
* too:
*/
locking_selftest();
/*
* This needs to be called before any devices perform DMA
* operations that might use the SWIOTLB bounce buffers. It will
* mark the bounce buffers as decrypted so that their usage will
* not cause "plain-text" data to be decrypted when accessed.
*/
mem_encrypt_init();
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start && !initrd_below_start_ok &&
page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
page_to_pfn(virt_to_page((void *)initrd_start)),
min_low_pfn);
initrd_start = 0;
}
#endif
page_ext_init();
kmemleak_init();
debug_objects_mem_init();
setup_per_cpu_pageset();
numa_policy_init();
acpi_early_init();
if (late_time_init)
late_time_init();
calibrate_delay();
pid_idr_init();
anon_vma_init();
#ifdef CONFIG_X86
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_enter_virtual_mode();
#endif
thread_stack_cache_init();
cred_init();
fork_init();
proc_caches_init();
buffer_init();
key_init();
security_init();
dbg_late_init();
vfs_caches_init();
pagecache_init();
signals_init();
proc_root_init();
nsfs_init();
cpuset_init();
cgroup_init();
taskstats_init_early();
delayacct_init();
check_bugs();
acpi_subsystem_init();
arch_post_acpi_subsys_init();
sfi_init_late();
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
efi_free_boot_services();
}
/* Do the rest non-__init'ed, we're now alive */
rest_init();
}
其中每个函数都可以做非常非常庞大的展开描述,此文只做当前函数用途说明不做具体详细展开。具体详细将在专项中进行。
1.1.1 set_task_stack_end_magic
第一个函数是set_task_stack_end_magic(&init_task);//该函数定义于kernel/fork.c文件
其中init_task结构体定义在文件init/init_task.c中,
/*
* Set up the first task table, touch at your own risk!. Base=0,
* limit=0x1fffff (=2MB)
*/
struct task_struct init_task
#ifdef CONFIG_ARCH_TASK_STRUCT_ON_STACK
__init_task_data
#endif
= {
#ifdef CONFIG_THREAD_INFO_IN_TASK
.thread_info = INIT_THREAD_INFO(init_task),
.stack_refcount = ATOMIC_INIT(1),
#endif
.state = 0,
.stack = init_stack,
.usage = ATOMIC_INIT(2),
.flags = PF_KTHREAD,
.prio = MAX_PRIO - 20,
.static_prio = MAX_PRIO - 20,
.normal_prio = MAX_PRIO - 20,
.policy = SCHED_NORMAL,
.cpus_allowed = CPU_MASK_ALL,
.nr_cpus_allowed= NR_CPUS,
.mm = NULL,
.active_mm = &init_mm,
.restart_block = {
.fn = do_no_restart_syscall,
},
.se = {
.group_node = LIST_HEAD_INIT(init_task.se.group_node),
},
.rt = {
.run_list = LIST_HEAD_INIT(init_task.rt.run_list),
.time_slice = RR_TIMESLICE,
},
.tasks = LIST_HEAD_INIT(init_task.tasks),
#ifdef CONFIG_SMP
.pushable_tasks = PLIST_NODE_INIT(init_task.pushable_tasks, MAX_PRIO),
#endif
#ifdef CONFIG_CGROUP_SCHED
.sched_task_group = &root_task_group,
#endif
.ptraced = LIST_HEAD_INIT(init_task.ptraced),
.ptrace_entry = LIST_HEAD_INIT(init_task.ptrace_entry),
.real_parent = &init_task,
.parent = &init_task,
.children = LIST_HEAD_INIT(init_task.children),
.sibling = LIST_HEAD_INIT(init_task.sibling),
.group_leader = &init_task,
RCU_POINTER_INITIALIZER(real_cred, &init_cred),
RCU_POINTER_INITIALIZER(cred, &init_cred),
.comm = INIT_TASK_COMM,
.thread = INIT_THREAD,
.fs = &init_fs,
.files = &init_files,
.signal = &init_signals,
.sighand = &init_sighand,
.nsproxy = &init_nsproxy,
.pending = {
.list = LIST_HEAD_INIT(init_task.pending.list),
.signal = {{0}}
},
.blocked = {{0}},
.alloc_lock = __SPIN_LOCK_UNLOCKED(init_task.alloc_lock),
.journal_info = NULL,
INIT_CPU_TIMERS(init_task)
.pi_lock = __RAW_SPIN_LOCK_UNLOCKED(init_task.pi_lock),
.timer_slack_ns = 50000, /* 50 usec default slack */
.pids = {
[PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID),
[PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID),
[PIDTYPE_SID] = INIT_PID_LINK(PIDTYPE_SID),
},
.thread_group = LIST_HEAD_INIT(init_task.thread_group),
.thread_node = LIST_HEAD_INIT(init_signals.thread_head),
#ifdef CONFIG_AUDITSYSCALL
.loginuid = INVALID_UID,
.sessionid = (unsigned int)-1,
#endif
#ifdef CONFIG_PERF_EVENTS
.perf_event_mutex = __MUTEX_INITIALIZER(init_task.perf_event_mutex),
.perf_event_list = LIST_HEAD_INIT(init_task.perf_event_list),
#endif
#ifdef CONFIG_PREEMPT_RCU
.rcu_read_lock_nesting = 0,
.rcu_read_unlock_special.s = 0,
.rcu_node_entry = LIST_HEAD_INIT(init_task.rcu_node_entry),
.rcu_blocked_node = NULL,
#endif
#ifdef CONFIG_TASKS_RCU
.rcu_tasks_holdout = false,
.rcu_tasks_holdout_list = LIST_HEAD_INIT(init_task.rcu_tasks_holdout_list),
.rcu_tasks_idle_cpu = -1,
#endif
#ifdef CONFIG_CPUSETS
.mems_allowed_seq = SEQCNT_ZERO(init_task.mems_allowed_seq),
#endif
#ifdef CONFIG_RT_MUTEXES
.pi_waiters = RB_ROOT_CACHED,
.pi_top_task = NULL,
#endif
INIT_PREV_CPUTIME(init_task)
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
.vtime.seqcount = SEQCNT_ZERO(init_task.vtime_seqcount),
.vtime.starttime = 0,
.vtime.state = VTIME_SYS,
#endif
#ifdef CONFIG_NUMA_BALANCING
.numa_preferred_nid = -1,
.numa_group = NULL,
.numa_faults = NULL,
#endif
#ifdef CONFIG_KASAN
.kasan_depth = 1,
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
.softirqs_enabled = 1,
#endif
#ifdef CONFIG_LOCKDEP
.lockdep_recursion = 0,
#endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.ret_stack = NULL,
#endif
#if defined(CONFIG_TRACING) && defined(CONFIG_PREEMPT)
.trace_recursion = 0,
#endif
#ifdef CONFIG_LIVEPATCH
.patch_state = KLP_UNDEFINED,
#endif
#ifdef CONFIG_SECURITY
.security = NULL,
#endif
};
EXPORT_SYMBOL(init_task);
继续看set_task_stack_end_magic函数,定义在kernel/fork.c文件中:
void set_task_stack_end_magic(struct task_struct *tsk)
{
unsigned long *stackend;
stackend = end_of_stack(tsk);
*stackend = STACK_END_MAGIC; /* for overflow detection */
}
获取栈边界地址,然后把 STACK_END_MAGIC这个宏设置为栈溢出的标志。
1.1.2 smp_setup_processor_id
接着来看函数smp_setup_processor_id(),
void __init __weak smp_setup_processor_id(void)
{
}
该函数是个空函数。
weak属性可以让编译器在编译的时候忽略函数未定义的错误。如果两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak symbol(弱符号),则这些全局符号不会引发重定义错误。链接器会忽略弱符号,去使用普通的全局符号来解析所有对这些符号的引用,但当普通的全局符号不可用时,链接器会使用弱符号。当有函数或变量名可能被用户覆盖时,该函数或变量名可以声明为一个弱符号。
有些架构比如arm是有自己的smp_setup_processor_id函数的(位于文件arch/arm64/kernel/setup.c),相当于上面所说的普通全局符号,这种情况下连接器就会忽略init/main.c中的smp_setup_processor_id函数。在x86架构,这时smp_setup_processor_id为空。
1.1.3 debug_objects_early_init
接下去我们看下debug_objects_early_init函数,定义在include/linux/debugobjects.h。
函数用于内核的对象调试。依赖配置CONFIG_DEBUG_OBJECTS。
如下:
#ifdef CONFIG_DEBUG_OBJECTS
extern void debug_objects_early_init(void);
….
#else
static inline void debug_objects_early_init(void) { }
….
#endif
如果定义了CONFIG_DEBUG_OBJECTS, 则使用外部定义的函数,位于文件lib/debugobjects.c,如下:
/*
* Called during early boot to initialize the hash buckets and link
* the static object pool objects into the poll list. After this call
* the object tracker is fully operational.
*/
void __init debug_objects_early_init(void)
{
int i;
for (i = 0; i < ODEBUG_HASH_SIZE; i++)
raw_spin_lock_init(&obj_hash[i].lock);
for (i = 0; i < ODEBUG_POOL_SIZE; i++)
hlist_add_head(&obj_static_pool[i].node, &obj_pool);
}
该函数初始化obj_hash、obj_static_pool这2个全局变量,这2个全局变量会在调试的时候用到。
1.1.4 cgroup_init_early
cgroup_init_early()这个函数就是初始化cgroup所需要的参数的。
受限于参数CONFIG_CGROUPS,如果没有则为空函数,如果定义该参数则使用kernel/cgroup/cgroup.c文件中的函数
/**
* cgroup_init_early - cgroup initialization at system boot
*
* Initialize cgroups at system boot, and initialize any
* subsystems that request early init.
*/
int __init cgroup_init_early(void)
{
static struct cgroup_sb_opts __initdata opts;
struct cgroup_subsys *ss;
int i;
init_cgroup_root(&cgrp_dfl_root, &opts);
cgrp_dfl_root.cgrp.self.flags |= CSS_NO_REF;
RCU_INIT_POINTER(init_task.cgroups, &init_css_set);
for_each_subsys(ss, i) {
WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->id,
"invalid cgroup_subsys %d:%s css_alloc=%p css_free=%p id:name=%d:%s\n",
i, cgroup_subsys_name[i], ss->css_alloc, ss->css_free,
ss->id, ss->name);
WARN(strlen(cgroup_subsys_name[i]) > MAX_CGROUP_TYPE_NAMELEN,
"cgroup_subsys_name %s too long\n", cgroup_subsys_name[i]);
ss->id = i;
ss->name = cgroup_subsys_name[i];
if (!ss->legacy_name)
ss->legacy_name = cgroup_subsys_name[i];
if (ss->early_init)
cgroup_init_subsys(ss, true);
}
return 0;
}
如果要研究cgroup,可以从这个函数入手。
1.1.5 local_irq_disable
local_irq_disable()函数屏蔽当前CPU上的所有中断,初始化没结束,直接接受中断可能会带来意想不到的惊喜,所以必须要屏蔽掉。等初始化结束在使能之。
#define local_irq_disable() \
do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0)
1.1.6 boot_cpu_init()
该函数位于kernel/cpu.c文件中,正如注释说明,用于激活第一个处理器。
/*
* Activate the first processor.
*/
void __init boot_cpu_init(void)
{
int cpu = smp_processor_id();
/* Mark the boot cpu "present", "online" etc for SMP and UP case */
set_cpu_online(cpu, true);
set_cpu_active(cpu, true);
set_cpu_present(cpu, true);
set_cpu_possible(cpu, true);
#ifdef CONFIG_SMP
__boot_cpu_id = cpu;
#endif
}
默认第一个CPU是boot CPU.
1.1.7 page_address_init()
page_address_init函数在内存都能够直接映射的时候不做任何事情,也就定义为空,否则就是mm/highmem.c中所定义的函数。
该函数定义在include/linux/mm.h,如果定义了参数WANT_PAGE_VIRTUAL则如下.
#define page_address_init() do { } while(0)
如果定义了HASHED_PAGE_VIRTUAL,则使用在文件mm/highmem.c中:
void __init page_address_init(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) {
INIT_LIST_HEAD(&page_address_htable[i].lh);
spin_lock_init(&page_address_htable[i].lock);
}
}
page_address_pool和page_address_htable[] 全局变量,
其中page_address_pool是一个列表头,用于指向相互连接的结构体page_address_map。
结构体page_address_map保存结构体page和它的虚拟内存关系. 如果页本来就是线性的那就会产生浪费了。
但是当地址被哈希之后,这个就非常有必要了。page_address_htable[] 是哈希表,由page_address_init()函数初始化。
1.1.8 setup_arch(&command_line)
setup_arch(&command_line)函数,用于完成内存映像的初始化,其中command_line是从bootloader中传下来的。
1.1.9 add_latent_entropy();
定义如下,当参数CONFIG_GCC_PLUGIN_LATENT_ENTROPY定义,而__CHECKER__没有定义,其实就是函数add_device_randomness。
#if defined(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) && !defined(__CHECKER__)
static inline void add_latent_entropy(void)
{
add_device_randomness((const void *)&latent_entropy,
sizeof(latent_entropy));
}
#else
static inline void add_latent_entropy(void) {}
#endif
1.1.10 add_device_randomness
函数,定义在drivers/char/random.c文件中,
add_device_randomness(command_line, strlen(command_line));
Linux 内核采用熵来描述数据的随机性,熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大。
Linux内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。可以实现产生真随机数序列。
1.1.11 boot_init_stack_canary()
函数初始化堆栈保护的canary值,用来防止栈溢出攻击。
1.1.12 mm_init_cpumask(&init_mm)
定义在文件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
cpumask_clear(mm->cpu_vm_mask_var);
}
初始化init_mm结构体,每一个任务都有一个mm_struct结构以管理内存空间,init_mm是内核的mm_struct。填充mm_struct结构体的相关变量。
1.1.13 setup_command_line(command_line)
函数位于文件init/main.c中,
/*
* We need to store the untouched command line for future reference.
* We also need to store the touched command line since the parameter
* parsing is performed in place, and we should allow a component to
* store reference of name/value for future reference.
*/
static void __init setup_command_line(char *command_line)
{
saved_command_line =
memblock_virt_alloc(strlen(boot_command_line) + 1, 0);
initcall_command_line =
memblock_virt_alloc(strlen(boot_command_line) + 1, 0);
static_command_line = memblock_virt_alloc(strlen(command_line) + 1, 0);
strcpy(saved_command_line, boot_command_line);
strcpy(static_command_line, command_line);
}
保存command line以备将来使用。
1.1.14 setup_nr_cpu_ids()
和CONFIG_SMP配置相关。
#ifndef CONFIG_SMP
…
static inline void setup_nr_cpu_ids(void) { }
#endif
如果定义该参数,函数则如下(kernel/smp.c):
/* An arch may set nr_cpu_ids earlier if needed, so this would be redundant */
void __init setup_nr_cpu_ids(void)
{
nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
}
1.1.15 setup_per_cpu_areas()
该函数为每个cpu的per-cpu变量副本分配空间
设置SMP体系每个CPU使用的内存空间,同时拷贝初始化段里数据,在mm/percpu.c中有实现,
1.1.16 boot_cpu_state_init()
1.1.17 smp_prepare_boot_cpu()
/* arch-specific boot-cpu hooks */
1.1.18 build_all_zonelists(NULL)
初始化所有内存管理节点列表,以便后面进行内存管理初始化
建立系统内存页区链表
1.1.19 page_alloc_init();
内存页初始化
设置内存分页分配通知器,在mm/page_alloc.c中有实现
1.1.20 parse_early_param()
解析需要早起处理的启动参数
1.1.21 parse_args
对传入内核参数进行解释,如果不能识别的命令就调用最后参数的函数,在kernel/params.c中实现
after_dashes = parse_args("Booting kernel",
static_command_line, __start___param,
__stop___param - __start___param,
-1, -1, NULL, &unknown_bootoption);解析cmdline中启动参数
if (!IS_ERR_OR_NULL(after_dashes))
parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
NULL, set_init_arg);
jump_label_init();处理静态定义在跳转标号
setup_log_buf(0);使用memblock_alloc分配一个启动的log缓冲区
1.1.22 vfs_caches_init_early();
虚拟文件系统的早期初始化,包括dentry和inode的hash表初始化工作,在fs/dcache.c中实现
1.1.23 sort_main_extable()
对内核异常向量表进行排序,位于kernel/extable.c中实现
1.1.24 trap_init()
对内核陷阱异常进程初始化
1.1.25 mm_init()
初始化内核内存分配器,过度到伙伴系统,启动slab机制,初始化非连续内存区
1.1.26 ftrace_init()
功能跟踪调试机制初始化,初始化内核跟踪模块。ftrace的作用是帮助开发人员了解Linux内核的运行时行为,以便于进行故障调试或者性能分析。
1.1.27 early_trace_init()
使能trace_printk
1.1.28 sched_init()
初始化进程调度器数据结构并创建运行队列,在kernel/sched/core.c中。
1.1.29 preempt_disable()
禁止进程内核抢占,早期启动时期,调度是极其脆弱的,在include/linux/preempt.h中实现
1.1.30 radix_tree_init()
初始化radix树算法初始化,在lib/radix_tree.c中实现
1.1.31 workqueue_init_early();
工作队列早期初始化, kernel/workqueue.c文件
1.1.32 rcu_init()
初始化rcu机制,读写拷贝
1.1.33 trace_init()
跟踪事件初始化
1.1.34 early_irq_init();
早期外部中断描述初始化,在kernel/irq/irqdesc.c中有实现,在kernel/softirq.c中直接return0
1.1.35 init_IRQ();
架构相关中断初始化,在arch/arm/kernel/irq.c中实现
1.1.36 tick_init()
初始化时钟滴答控制器
1.1.37 init_timers()
初始化引导CPU的时钟相关的数据结构,在kernel/timer.c中实现
1.1.38 hrtimers_init();
初始化高精度的定时器,在kernel/hrtimer.c中实现
1.1.39 softirq_init()
初始化软件软件中断,在kernel/softirq.c中实现
1.1.40 timekeeping_init()
初始化系统时钟计时,在kernel/time/timekeeping.c中实现
1.1.41 time_init()
初始化系统时钟,在arch/arm/kernel/time.c中实现
1.1.42 sched_clock_postinit()
对每个CPU进行系统进程调度时钟初始化。
1.1.43 printk_safe_init();
位于文件kernel/printk/printk_safe.c,
1.1.44 profile_init()
profile初始化,profile是内核诊断工具,在include/linux/profile.h中直接return0,在kernel/profile.c中有实现
1.1.45 call_function_init()
在include/linux/amp.h中为空, 在kernel/smp.c中有实现
1.1.46 kmem_cache_init_late()
slab分配器后期初始化,在mm/slob.c、slub.c、slab.c中有实现
内核启动时使用临时内存分配器bootmem,之后由slab接管。kmem_cache_init_late()初始化了slab分配器(内核高速缓存分配器),这意味着bootmem的结束,同时内核的内存管理系统正式开始工作。bootmem的分配必须先于kmem_cache_init_late()。
1.1.47 console_init()
控制台初始化。从这个函数之后就可以输出内容到控制台了。在此之前的输出保存在输出缓冲区中,这个函数被调用之后就马上把之前的内容输出出来。
在include/linux/tty.h中为空,在drivers/tty/tty_io.c中实现
1.1.48 lockdep_info()
如果定义了CONFIG_LOCKDEP宏,那么就打印锁依赖信息,进行自我检测,否则什么也不做 。在include/linux/lockdep.h中为空,在kernel/lockdep.c中有实现
1.1.49 locking_selftest()
如果定义CONFIG_DEBUG_LOCKING_API_SELFTESTS宏 //则locking_selftest()是一个空函数,否则执行锁自测
1.1.50 mem_encrypt_init();
位于arch/x86/mm/mem_encrypt.c文件中,替换__weak函数。
1.1.51 page_ext_init();
和参数CONFIG_SPARSEMEM相关,函数位于mm/page_ext.c中。
1.1.52 kmemleak_init()
内存泄漏检测机制的初始化,空函数,在include/linux/kmemleak.h中为空,在mm/kmemleak.c中实现。
1.1.53 debug_objects_mem_init()
创建调试对象内存缓存,空函数,在include/linux/debugobjects.h为空,在lib/debugobjects.c中实现
1.1.54 setup_per_cpu_pageset();
位于文件mm/page_alloc.c中,为每个CPU分配页集合,并初始化
1.1.55 numa_policy_init()
初始化NUMA的内存访问策略。提高多个CPU的内存访问速度。多个CPU访问同一个节点的内存速度比访问多个节点的内存速度大得多。
1.1.56 acpi_early_init();
drivers/acpi/bus.c文件中,acpi早期初始化
1.1.57 calibrate_delay()
主要计算CPU需要校准的时间。
1.1.58 pid_idr_init();
kernel/pid.c文件中,初始化idr。
1.1.59 anon_vma_init()
初始化EFI的接口,并进入虚拟模式。
1.1.60 EFI_RUNTIME_SERVICES
只支持x86。
#ifdef CONFIG_X86
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_enter_virtual_mode();
#endif
最后调用如下
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
efi_free_boot_services();
}
1.1.61 thread_stack_cache_init()
kernel/fork.c,进程栈缓存初始化,当
# if THREAD_SIZE >= PAGE_SIZE
使用__weak函数。
1.1.62 cred_init()
任务信用系统初始化,在kernel/cred.c中实现
1.1.63 fork_init()
根据当前物理内存计算出来可以创建进程(线程)的最大数量,并进行进程环境初始化,为task_struct分配空间。进程创建机制初始化,在kernel/fork.c中实现
1.1.64 proc_caches_init()
进程缓存初始化,在kernel/fork.c中实现
1.1.65 buffer_init()
文件系统的缓存区初始化,在include/linux/buffer_head.h中为空,在fs/buffer.c中实现
1.1.66 key_init()
初始化内核安全键管理列表和结构,内核秘钥管理系统。
1.1.67 security_init()
初始化内核安全管理框架,以便提供文件\登陆等权限。
1.1.68 dbg_late_init()
内核调试系统后期初始化。
1.1.69 vfs_caches_init()
虚拟文件系统进行缓存初始化,提高虚拟文件系统的访问速度。
1.1.70 pagecache_init();
mm/filemap.c文件中,完成页缓存初始化
1.1.71 signals_init();
位于文件kernel/signal.c中,完成信号初始化
1.1.72 proc_root_init()
初始化系统进程文件系统,主要提供内核与用户进行交互的平台,方便用户实时查看进程的信息。
1.1.73 nsfs_init();
初始化nsfs,位于文件fs/nsfs.c
1.1.74 cpuset_init()
初始化CPUSET。CPUSET主要为控制组提供CPU和内存节点的管理的结构。
1.1.75 cgroup_init()
进程控制组正式初始化,主要用来为进程和它的子进程提供性能控制。
1.1.76 taskstats_init_early()
任务状态早期初始化,为结构体获取高速缓存,并初始化互斥机制。
1.1.77 delayacct_init()
任务延迟机制初始化,初始化每个任务延时计数。当一个任务等待CPU或者IO同步的时候,都需要计算等待时间。
1.1.78 check_bugs()
检查CPU配置、FPU等是否非法使用不具备的功能,检查CPU BUG,软件规避BUG。
1.1.79 apci子系统
acpi_subsystem_init();
acpi子系统初始化,位于文件drivers/acpi/bus.c
arch_post_acpi_subsys_init();
架构相关的,acpi子系统初始化,位于文件arch/x86/kernel/process.c中。
1.1.80 sfi_init_late()
simple fireware interface 初始化,在include/linux/sfi.h中为空,在drivers/sfi/sfi_core.c中实现
1.1.81 rest_init()函数
最后一个初始化函数,负责内核的其余初始化工作。