发布时间:2022-11-24 18:30
/*
* 使用大量bootmem分配,且必须先于
* kmem_cache_init()
*/
点击(此处)折叠或打开
以上注释的含义在于bootmem是内核启动时使用的临时内存分配器。之后由slab接替。
kmem_cache_init()初始化了内核高速缓存分配器(slab分配器),这个函数标标志着bootmem的终结,同时内核的内存管理系统正式启用了。
所以在kmem_cache_init()之后,bootmem的API不再可用,所以bootmem分配必须先于kmem_cache_init()。
setup_log_buf(0);
点击(此处)折叠或打开
使用bootmem分配一个记录启动信息的缓存区
pidhash_init();
点击(此处)折叠或打开
使用bootmem分配并初始化PID散列表,由PID分配器管理空闲和已指派的PID
vfs_caches_init_early();
点击(此处)折叠或打开
前期VFS缓存初始化
sort_main_extable();
点击(此处)折叠或打开
对内核异常表( exception table )按照异常向量号大小进行排序。
trap_init();
点击(此处)折叠或打开
对内核陷阱异常进行初始化,在ARM构架中为空函数。
mm_init();
点击(此处)折叠或打开
初始化内核内存分配器,其包含6个子函数,作用如下:
1、page_cgroup_init_flatmem(); 获取page_cgroup 所需内存
2、mem_init(); 关闭并释放bootmem分配器,打印内存信息。在内核启动时看到的类似如下信息,就是其子函数mem_init输出的:
点击(此处)折叠或打开
Memory: 86MB 39MB = 125MB total
Memory: 120768k/120768k available, 99392k reserved, 0K highmem
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
DMA : 0xffc00000 - 0xffe00000 ( 2 MB)
vmalloc : 0xde800000 - 0xf8000000 ( 408 MB)
lowmem : 0xc0000000 - 0xde400000 ( 484 MB)
pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
.init : 0xc0008000 - 0xc003b000 ( 204 kB)
.text : 0xc003b000 - 0xc04c0000 (4628 kB)
.data : 0xc04c0000 - 0xc0501a80 ( 263 kB)
3、kmem_cache_init(); 初始化slab分配器
4、percpu_init_late(); PerCPU变量系统后期初始化
5、pgtable_cache_init();页表缓存初始化,对于ARM,“介是一个空函数”
6、vmalloc_init();初始化虚拟内存分配器
/*
* 在开启任何中断(比如定时器中断)前设置调度器。
* 完整的拓扑设置发生在smp_init()中
*-但与此同时,我们仍然有一个正常运作的调度器。
*/
sched_init();
点击(此处)折叠或打开
初始化调度器数据结构,并创建运行队列
/*
* 禁用强占 - 早期启动时的调度是极为脆弱的,
*直到cpu_idle()的首次运行。
*/
preempt_disable();
if (!irqs_disabled()) {
printk(KERN_WARNING "start_kernel(): bug: interrupts were "
"enabled *very* early, fixing it\n");
local_irq_disable();
}
点击(此处)折叠或打开
在启动的初期关闭抢占和中断。
idr_init_cache();
点击(此处)折叠或打开
为IDR机制分配缓存,主要是为struct idr_layer结构体分配空间
perf_event_init();
点击(此处)折叠或打开
CPU性能监视机制初始化
此机制包括CPU同一时间执行指令数,cache miss数,分支预测失败次数等性能参数
rcu_init();
点击(此处)折叠或打开
内核RCU(Read-Copy Update:读取-复制-更新)机制初始化
radix_tree_init();
点击(此处)折叠或打开
内核radix树算法初始化
/* 在init_ISA_irqs()之前初始化一些链接 */
early_irq_init();
init_IRQ();
点击(此处)折叠或打开
硬件中断系统初始化:
early_irq_init();前期外部中断描述符初始化,主要初始化数据结构。
init_IRQ;对应构架特定的中断初始化函数,在ARM构架中:
点击(此处)折叠或打开
void __init init_IRQ(void)
{
machine_desc->init_irq();
}
也就是运行设备描述结构体中的init_irq函数,此函数一般在板级初始化文件(arch/*/mach-*/board-*.c)中定义。
prio_tree_init();
点击(此处)折叠或打开
初始化内核基于radix数的优先级搜索树(PST),主要是对其结构体进行初始化。
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
点击(此处)折叠或打开
以上几个函数主要是初始化内核的软中断及时钟机制:
前面几个函数主要是注册一些内核通知函数到cpu和hotcpu通知链,并开启部分软中断(tasklet等)。
最后的time_init是构架相关的,旨在开启一个硬件定时器,开始产生系统时钟。对于ARM构架:
点击(此处)折叠或打开
void __init time_init(void)
{
system_timer = machine_desc->timer;
system_timer->init();
#ifdef CONFIG_HAVE_SCHED_CLOCK
sched_clock_postinit();
#endif
}
其实就是调用板级初始化文件(arch/arm/mach-*/board-*.c)中定义“设备描述结构体”中的timer成员的初始化函数。
profile_init();
点击(此处)折叠或打开
初始化内核profile子系统,她是内核的性能调试工具。
call_function_init();
点击(此处)折叠或打开
初始化所有CPU的call_single_queue(具体作用还没搞明白),并注册CPU热插拔通知函数到CPU通知链中。
if (!irqs_disabled())
printk(KERN_CRIT "start_kernel(): bug: interrupts were "
"enabled early\n");
early_boot_irqs_disabled = false;
local_irq_enable();
点击(此处)折叠或打开
检测硬件中断是否开启,如果开启了就打印出警告。
设置启动早期IRQ使能标志,允许IRQ使能。
最后开启总中断(ARM构架是这样,其他构架可能也是这个意思)。
/* 中断已经开启,因此所有GFP分配是安全的. */
gfp_allowed_mask = __GFP_BITS_MASK;
点击(此处)折叠或打开
开启所有GFP分配允许标志
GFP(get free page)
kmem_cache_init_late();
点击(此处)折叠或打开
slab分配器的后期初始化。如果使用的是slob或slub,则为空函数。
/*
* HACK ALERT! hack警告!这个是早期的。我们在完成PCI设置等工作前
* 使能控制台,且console_init()必须意识到这个。
* 但是我们的确想要早点输出信息,以防某些错误的发生。
*/
console_init();
点击(此处)折叠或打开
初始化控制台,这样可以早点看到启动信息,避免出错时无法查找原因。
if (panic_later)
panic(panic_later, panic_param);
点击(此处)折叠或打开
检查内核恐慌标志。如果出了问题,就打印信息。
lockdep_info();
点击(此处)折叠或打开
打印lockdep调试模块的信息。
/*
* 当irq使能的时候必须运行这个函数,因为它也要自检
* [hard/soft]-irqs 开/关 锁反转的bug:
*
*/
locking_selftest();
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start && !initrd_below_start_ok &&
page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
printk(KERN_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
点击(此处)折叠或打开
检查initrd的位置是否符合要求。
min_low_pfn是系统可用的最小的pfn(页帧号)。
也就是判断传递进来initrd_start对应的物理地址是否正常。如果有误就打印错误信息,并清零initrd_start。
page_cgroup_init();
点击(此处)折叠或打开
mem_cgroup是cgroup体系中提供的用于memory隔离的功能,此处对此功能进行初始化。
enable_debug_pagealloc();
点击(此处)折叠或打开
使能页分配的调试标志。
debug_objects_mem_init();
点击(此处)折叠或打开
debug objects机制的内存分配初始化
kmemleak_init();
点击(此处)折叠或打开
内核内存泄漏检测机制初始化;
setup_per_cpu_pageset();
点击(此处)折叠或打开
设置每个CPU的页组,并初始化。此前只有启动页组。
numa_policy_init();
点击(此处)折叠或打开
非一致性内存访问(NUMA)初始化
if (late_time_init)
late_time_init();
点击(此处)折叠或打开
如果构架存在此函数,就调用后期时间初始化。
sched_clock_init();
点击(此处)折叠或打开
对每个CPU,初始化调度时钟。
calibrate_delay();
点击(此处)折叠或打开
计算BogoMIPS值,他是衡量一个CPU性能的标志。
pidmap_init();
点击(此处)折叠或打开
PID分配映射初始化。
anon_vma_init();
点击(此处)折叠或打开
匿名虚拟内存域( anonymous VMA)初始化
#ifdef CONFIG_X86
if (efi_enabled)
efi_enter_virtual_mode();
#endif
thread_info_cache_init();
点击(此处)折叠或打开
获取thread_info缓存空间,大部分构架为空函数(包括ARM)
cred_init();
点击(此处)折叠或打开
任务信用系统初始化。详见:Documentation/credentials.txt
fork_init(totalram_pages);
点击(此处)折叠或打开
进程创建机制初始化。为内核"task_struct"分配空间,计算最大任务数。
proc_caches_init();
点击(此处)折叠或打开
初始化进程创建机制所需的其他数据结构,为其申请空间。
buffer_init();
点击(此处)折叠或打开
缓存系统初始化,创建缓存头空间,并检查其大小限时。
key_init();
点击(此处)折叠或打开
内核密匙管理系统初始化。
security_init();
点击(此处)折叠或打开
内核安全框架初始化
dbg_late_init();
点击(此处)折叠或打开
内核调试系统后期初始化
vfs_caches_init(totalram_pages);
点击(此处)折叠或打开
虚拟文件系统(VFS)缓存初始化
signals_init();
点击(此处)折叠或打开
信号管理系统初始化
/* 根文件系统的填充可能需要也回写机制 */
page_writeback_init();
点击(此处)折叠或打开
页回写机制初始化
#ifdef CONFIG_PROC_FS
proc_root_init();
#endif
点击(此处)折叠或打开
proc文件系统初始化
cgroup_init();
点击(此处)折叠或打开
control group的正式初始化
cpuset_init();
点击(此处)折叠或打开
taskstats_init_early();
点击(此处)折叠或打开
任务状态早期初始化函数:为结构体获取高速缓存,并初始化互斥机制。
delayacct_init();
点击(此处)折叠或打开
任务延迟机制初始化
check_bugs();
点击(此处)折叠或打开
检查CPU BUG的函数,通过软件规避BUG
acpi_early_init(); /* 在 LAPIC 和 SMP 前初始化 */
点击(此处)折叠或打开
ACPI早期初始化函数。
ACPI - Advanced Configuration and Power Interface高级配置及电源接口
sfi_init_late();
点击(此处)折叠或打开
ftrace_init();
点击(此处)折叠或打开
/* 所剩下的非-__init的初始化, 内核现在已经启动了 */
rest_init();
点击(此处)折叠或打开
虽然从名字上来说是剩余的初始化。
但是这个函数中的初始化包含了很多的内容,后面我回单独写一篇来分析。
}