//Linux内核由 start_kernel开始,到用户进程init 结束 调用了一系列的初始化函数 对所有的内核组件
//进行初始化 其中 start_kernel rest_init kernel_init init_post 等4个初始化函数 构成了整个
//初始化的主线
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern struct kernel_param __start___param[], __stop___param[];
//设置对称多处理器的id,返回启动的cpu的id
//当只有一个cpu时什么也不做
smp_setup_processor_id();
/*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
//这个函数的主要作用是对调用的栈的调试功能进一步初始化,在arm系统里是空函数
unwind_init();
//
lockdep_init();
//关闭当前cpu的所有中断响应。在arm里主要是对cpsr寄存器进行操作
local_irq_disable();
//这个函数主要作用是标记内核还是在早期初始化代码阶段,并且中断在关闭状态
//如果有任何中断打开或是请求中断的事情出现,都会提出警告,以便跟踪代码
//错误情况。早期代码结束之后,会调用early_boot_irqs_on()来设置这个标志为真
early_boot_irqs_off();
//这个函数主要作用是对中断请求描述符进行锁的早期初始化。在arm里,这个函数
//没有任何代码
early_init_irq_lock_class();
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
//初始化大内核锁。对于只能有一个cpu运行的代码,使用这样的一个锁,可以使一个
//cpu调用内核,而其他的cpu无法调用内核;并且,可以运行内核代码的这个cpu同时
//可以递归的调用内核去运行。
lock_kernel();
//初始化时钟事件管理器的回调函数,比如当时钟设备添加时处理。内核里定义俄罗时钟
//事件管理器,主要用来管理所有需要周期性的执行任务的设备
tick_init();
//设置当前引导系统的cpu在物理上存在,在逻辑上可以使用,并且初始化准备好。
//cpu_present_map位图 表示有多少个cpu,每一位表示一个cpu的存在。如果单cpu,则第
//0位设置为1。由于系统中可能有的cpu未初始化或者其他原因导致的不能使用,内核使用
//cpu_online_map 位图 表示可以运行内核代码和接受中断处理的cpu。由于系统中不一定
//所有cpu都参与工作,因此系统中引入cpu_possible_map位图表示最多可以使用的cpu
//本函数就是以次设置这三个位图标志
boot_cpu_init();
//初始化高端内存映射表。在32位的系统里,最多能访问的内存为4G,其中3G空间给应用
//程序,内核只占用1G空间。而实际上,比这个还要小,因为其中的一部分(128M)空间
//用来映射高端内存
page_address_init();
//在终端上输出显示注意信息 KERN_NOTICE宏的定义为 "<5>"
//在终端杀姑娘显示版本信息、编译的电脑用户名、编译起版本、编译时间
printk(KERN_NOTICE);
printk(linux_banner);
//对内核架构进行初始化。
//再次获取cpu类型和系统架构,分析引导程序传入的命令行参数,进行页面内存初始化
//处理器初始化,中断早期初始化等等
setup_arch(&command_line);
//保存命令行,以便后面的使用
setup_command_line(command_line);
//对调用栈的调试功能进一步的初始化,在arm里是空函数
unwind_setup();
//设置smp体系每个cpu使用的内存空间,同时拷贝初始化段里数据
setup_per_cpu_areas();
//为smp系统里引导cpu进行准备工作。在arm里是空函数
smp_prepare_boot_cpu();/* arch-specific boot-cpu hooks */
/*
* 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.
*/
//调度器的初始化,比如分配调度器占用的内存,初始化人物队列,设置当前任务的空线程
//当前人物的调度策略为CFS(Completely Fair Scheduler)调度器
sched_init();
/*
* Disable preemption - early bootup scheduling is extremely
* fragile until we cpu_idle() for the first time.
*/
//关闭优先级调度 。因为系统还没有完全初始化,不能使用优先级调度
preempt_disable();
//初始化所有内存管理节点列表,以便后面进行内存管理初始化
build_all_zonelists();
//设置内存页分配通知器
page_alloc_init();
printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
//分析早期使用的参数
parse_early_param();
//对传入内核的参数进行解析,如果有不能识别的命令就调用最后面一个参数所指示的
//函数
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
//判断是否中断已开启,如果是 就关闭中断 并且打印警告信息
if (!irqs_disabled()) {
printk(KERN_WARNING "start_kernel(): bug: interrupts were "
"enabled *very* early, fixing it\n");
local_irq_disable();
}
//对内核的异常表进行堆排序,以便加速访问
sort_main_extable();
//对异常进行初始化,在arm里是空函数
trap_init();
//初始化直接读拷贝更新的锁机制。rcu主要提供在读取数据机会多、更新比较少的场合
//这样减少读取数据锁的性能下降的问题
rcu_init();
//初始化中断相关的工作,主要初始化中断描述数组,然后调用每个cpu架构的中断初始化
init_IRQ();
//初始化进程id的hash表,这样可以提供通过pid进行高效访问进程结构的信息。Linux里
//共有4种类型的pid,因此有4种hash表相对应
pidhash_init();
//初始化引导cpu的时钟相关的数据结构,注册时钟的回调函数,当时钟到达时可以回调
//时钟处理函数,最后初始化时钟软件中断处理
init_timers();
//初始化高精度定时器,并设置回调函数
hrtimers_init();
//初始化软中断 。软中断与硬件中断在处理时的区别是:软件中断是使用线程来监视中断号
//而硬件中断是使用cpu硬件来监视中断
softirq_init();
//初始化系统时钟计时,并且初始化内核里与时钟计时相关的变量
timekeeping_init();
//初始化系统时钟
time_init();
//分配内核性能统计保存的内存,以便统计的性能变量可以保存到这里
profile_init();
if (!irqs_disabled())
printk("start_kernel(): bug: interrupts were enabled early\n");
//设置内核还在早期初始化阶段的标志,为方便调试而做
early_boot_irqs_on();
//打开本地cpu中断,即允许本cpu处理中断。如果有多个cpu,那么此处并不处理别的cpu
local_irq_enable();
/*
* 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(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:
*/
//测试锁的api是否正常,进行自我测试
locking_selftest();
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start && !initrd_below_start_ok &&
initrd_start < min_low_pfn << PAGE_SHIFT) {
printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
"disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
initrd_start = 0;
}
#endif
//初始化虚拟文件系统的缓存
vfs_caches_init_early();
//初始化cpu集合的内存分配变量 以便任务的内存分配于cpu集合进行比较,如果
//两者不一致,就更新任务的内存允许分配的内存大小
cpuset_init_early();
//标记哪些内存可用
mem_init();
//初始化内核内存的缓存,当初始化完成之后,就可以使用通用内存缓存了
kmem_cache_init();
//创建每个cpu的告诉缓存集合数组。因为每个cpu不定时需要使用一些页面内存和
//释放页面内存,为了提高效率,就预先创建了一些内存页面作为每个cpu页面集合
setup_per_cpu_pageset();
//初始化numa(NonUniform Memory Access Achitecture)的内存访问策略。
//主要用于提高多个cpu访问内存的速度。因为多个cpu访问同一个节点的内存速度
//远比访问多个节点的速度来的快
numa_policy_init();
//运行时钟相关后期的初始化功能
if (late_time_init)
late_time_init();
//计算cpu需要校准的时间(相对于引导cpu的执行时间)。对于非引导cpu才有用
calibrate_delay();
//初始化进程位图 一般情况下使用一页来表示所有进程占用情况
pidmap_init();
//页表缓存初始化
pgtable_cache_init();
//初始化优先搜索树
prio_tree_init();
//初始化反向映射的匿名内存,提供方向查找内存的结构指针位置,快速回首内存
anon_vma_init();
#ifdef CONFIG_X86
if (efi_enabled)
efi_enter_virtual_mode();
#endif
//根据当前牡蛎内存计算出可以创建的进程(线程)的数量,并进行进程环境初始化
fork_init(num_physpages);
//进程缓存初始化
proc_caches_init();
//初始化文件系统缓冲区,并计算最大可以使用的文件缓存
buffer_init();
unnamed_dev_init();
//初始化安全键管理列表和结构
key_init();
//初始化安全管理框架,以便提供访问文件/登录等权限
security_init();
//初始化虚拟文件系统缓存
vfs_caches_init(num_physpages);
//初始化radix树,radix树基于二进制键的查找树
radix_tree_init();
//初始化信号队列缓存
signals_init();
/* rootfs populating might need page-writeback */
page_writeback_init();
#ifdef CONFIG_PROC_FS
//初始化proc文件系统 主要提供内核与用户交互的平台
//方便用户实时查看进程的信息
proc_root_init();
#endif
//初始化CPUSET ,CPUSET主要为控制组提供CPU和内存节点
//管理的结构
cpuset_init();
//初始化任务状态相关的缓存、队列和信号量。任务状态主要向用户
//提供任务的状态信息
taskstats_init_early();
//初始化每个任务延时计数。当一个任务等待cpu、或者等待I/O同步时
//都需要计算等待时间
delayacct_init();
//检查cpu配置、fpu等是否非法使用不具备的功能
check_bugs();
//初始化acpi电源管理。
acpi_early_init(); /* before LAPIC and SMP init */
/* Do the rest non-__init'ed, we're now alive */
//后继初始化,主要是创建内核线程init,并运行。
rest_init();
}
linux 内核 之 start_kernel()
最新推荐文章于 2023-09-18 11:25:43 发布