张超《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

我的代码可见https://www.shiyanlou.com/courses/reports/986221

在这里我们用的是linux-3.18.6版本,以下简写成linux。

start_kernel在 /linux/init/main.c中定义:

这个函数是内核由引导程序引导以后,由自解压程序解压以后执行的第一个函数,可以认为是整个内核的入口函数,以后我分析的代码全部从这个函数开始!

这个函数做的事情相对比较简单,就是线性的初始化一些内核的基础机制,如中断,内存管理,进程管理,信号,文件系统,KO等!最后就启动一个init线程,init线程再读取文件系统里的init程序,做为系统的第一个进程而存在!

其实,start_kernel函数是0是做为0号进程存在的,它在最后就是空转CPU:

  1. 500asmlinkage __visible void __init start_kernel(void)
  2. {
  3. char *command_line;
  4. char *after_dashes;
  5.  
  6. /*
  7. 506 * Need to run as early as possible, to initialize the
  8. 507 * lockdep hash:
  9. 508 */
  10. lockdep_init();
  11. set_task_stack_end_magic(&init_task);
  12. smp_setup_processor_id();
  13. debug_objects_early_init();
  14.  
  15. /*
  16. 515 * Set up the the initial canary ASAP:
  17. 516 */
  18. boot_init_stack_canary();
  19.  
  20. cgroup_init_early();
  21.  
  22. local_irq_disable();
  23. early_boot_irqs_disabled = true;
  24.  
  25. /*
  26. 525 * Interrupts are still disabled. Do necessary setups, then
  27. 526 * enable them
  28. 527 */
  29. boot_cpu_init();
  30. page_address_init();
  31. pr_notice("%s", linux_banner);
  32. setup_arch(&command_line);
  33. mm_init_cpumask(&init_mm);
  34. setup_command_line(command_line);
  35. setup_nr_cpu_ids();
  36. setup_per_cpu_areas();
  37. smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
  38.  
  39. build_all_zonelists(NULL, NULL);
  40. page_alloc_init();
  41.  
  42. pr_notice("Kernel command line: %s\n", boot_command_line);
  43. parse_early_param();
  44. after_dashes = parse_args("Booting kernel",
  45. static_command_line, __start___param,
  46. __stop___param - __start___param,
  47. -, -, &unknown_bootoption);
  48. if (!IS_ERR_OR_NULL(after_dashes))
  49. parse_args("Setting init args", after_dashes, NULL, , -, -,
  50. set_init_arg);
  51.  
  52. jump_label_init();
  53.  
  54. /*
  55. 554 * These use large bootmem allocations and must precede
  56. 555 * kmem_cache_init()
  57. 556 */
  58. setup_log_buf();
  59. pidhash_init();
  60. vfs_caches_init_early();
  61. sort_main_extable();
  62. trap_init();
  63. mm_init();
  64.  
  65. /*
  66. 565 * Set up the scheduler prior starting any interrupts (such as the
  67. 566 * timer interrupt). Full topology setup happens at smp_init()
  68. 567 * time - but meanwhile we still have a functioning scheduler.
  69. 568 */
  70. sched_init();
  71. /*
  72. 571 * Disable preemption - early bootup scheduling is extremely
  73. 572 * fragile until we cpu_idle() for the first time.
  74. 573 */
  75. preempt_disable();
  76. if (WARN(!irqs_disabled(),
  77. "Interrupts were enabled *very* early, fixing it\n"))
  78. local_irq_disable();
  79. idr_init_cache();
  80. rcu_init();
  81. context_tracking_init();
  82. radix_tree_init();
  83. /* init some links before init_ISA_irqs() */
  84. early_irq_init();
  85. init_IRQ();
  86. tick_init();
  87. rcu_init_nohz();
  88. init_timers();
  89. hrtimers_init();
  90. softirq_init();
  91. timekeeping_init();
  92. time_init();
  93. sched_clock_postinit();
  94. perf_event_init();
  95. profile_init();
  96. call_function_init();
  97. WARN(!irqs_disabled(), "Interrupts were enabled early\n");
  98. early_boot_irqs_disabled = false;
  99. local_irq_enable();
  100.  
  101. kmem_cache_init_late();
  102.  
  103. /*
  104. 603 * HACK ALERT! This is early. We're enabling the console before
  105. 604 * we've done PCI setups etc, and console_init() must be aware of
  106. 605 * this. But we do want output early, in case something goes wrong.
  107. 606 */
  108. console_init();
  109. if (panic_later)
  110. panic("Too many boot %s vars at `%s'", panic_later,
  111. panic_param);
  112.  
  113. lockdep_info();
  114.  
  115. /*
  116. 615 * Need to run this when irqs are enabled, because it wants
  117. 616 * to self-test [hard/soft]-irqs on/off lock inversion bugs
  118. 617 * too:
  119. 618 */
  120. locking_selftest();
  121.  
  122. #ifdef CONFIG_BLK_DEV_INITRD
  123. if (initrd_start && !initrd_below_start_ok &&
  124. page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
  125. pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
  126. page_to_pfn(virt_to_page((void *)initrd_start)),
  127. min_low_pfn);
  128. initrd_start = ;
  129. }
  130. #endif
  131. page_cgroup_init();
  132. debug_objects_mem_init();
  133. kmemleak_init();
  134. setup_per_cpu_pageset();
  135. numa_policy_init();
  136. if (late_time_init)
  137. late_time_init();
  138. sched_clock_init();
  139. calibrate_delay();
  140. pidmap_init();
  141. anon_vma_init();
  142. acpi_early_init();
  143. #ifdef CONFIG_X86
  144. if (efi_enabled(EFI_RUNTIME_SERVICES))
  145. efi_enter_virtual_mode();
  146. #endif
  147. #ifdef CONFIG_X86_ESPFIX64
  148. /* Should be run before the first non-init thread is created */
  149. init_espfix_bsp();
  150. #endif
  151. thread_info_cache_init();
  152. cred_init();
  153. fork_init(totalram_pages);
  154. proc_caches_init();
  155. buffer_init();
  156. key_init();
  157. security_init();
  158. dbg_late_init();
  159. vfs_caches_init(totalram_pages);
  160. signals_init();
  161. /* rootfs populating might need page-writeback */
  162. page_writeback_init();
  163. proc_root_init();
  164. cgroup_init();
  165. cpuset_init();
  166. taskstats_init_early();
  167. delayacct_init();
  168.  
  169. check_bugs();
  170.  
  171. sfi_init_late();
  172.  
  173. if (efi_enabled(EFI_RUNTIME_SERVICES)) {
  174. efi_late_init();
  175. efi_free_boot_services();
  176. }
  177.  
  178. ftrace_init();
  179.  
  180. /* Do the rest non-__init'ed, we're now alive */
  181. rest_init();
  182. }

start_kernel代码

我们的实验截图在最后面;

我们规定【】显示的是所在的文件目录以及行数,默认是在/init/main.c中,都是在linux里;前面是在init/main.c的行号,后面是函数自己定义所在的目录及行数。

【502】 char * command_line;

/*命令行,用来存放bootloader传递过来的参数*/

【509】 lockdep_init(); 【kernel/locking/lockdep.c  3975】

/*建立一个哈希表(hash tables),就是一个前后指向的指针结构体数组。 (函数的主要作用是初始化锁的状态跟踪模块。由于内核大量使用锁来进行多进程多处理器的同步操作,死锁就会在代码不合理的时候出现,但是要定位哪个锁比较困难,用哈希表可以跟踪锁的使用状态。死锁情况:一个进程递归加锁同一把锁;同一把锁在两次中断中加锁;几把锁形成闭环死锁)*/

【510】set_task_stack_end_magic(&init_task); 【kernel/fork.c  297】

/*init_task即手工创建的PCB,0号进程即最终的idle进程*/

【511】 smp_setup_processor_id();  【473】

/*针对SMP处理器,用于获取当前CPU的硬件ID,如果不是多核,函数为空 (判断是否定义了CONFIG_SMP,如果定义了调用read_cpuid_mpidr读取寄存器CPUID_MPIDR的值,就是当前正在执行初始化的CPU ID,为了在初始化时做个区分,初始化完成后,所有处理器都是平等的,没有主从)*/

【512】debug_objects_early_init();【lib/debugobjects.c  1007】

/*初始化哈希桶(hash buckets)并将static object和pool object放入poll列表,这样堆栈就可以完全操作了 (这个函数的主要作用就是对调试对象进行早期的初始化,就是HASH锁和静态对象池进行初始化,执行完后,object tracker已经开始完全运作了)*/

【517】boot_init_stack_canary();【arch/x86/include/asm/stackprotector.h  58】

/*初始化堆栈保护的值,防止栈溢出*/

【519】cgroup_init_early();【kernel/cgroup.c  4882】

/*在系统启动时初始化cgroups,同时初始化需要early_init的子系统 (这个函数作用是控制组(control groups)早期的初始化,控制组就是定义一组进程具有相同资源的占有程度,比如,可以指定一组进程使用CPU为30%,磁盘IO为40%,网络带宽为50%。目的就是为了把所有进程分配不同的资源)*/

【521】local_irq_disable();【】

/*关闭当前CPU的所有中断响应,操作CPSR寄存器。对应后面的*/

【522】early_boot_irqs_disabled = true;

/*系统中断关闭标志,当early_init完毕后,会恢复中断设置标志为false。*/

【528】boot_cpu_init();【463】

/*设置当前引导系统的CPU在物理上存在,在逻辑上可以使用,并且初始化准备好,即激活当前CPU (在多CPU的系统里,内核需要管理多个CPU,那么就需要知道系统有多少个CPU,在内核里使用cpu_present_map位图表达有多少个CPU,每一位表示一个CPU的存在。如果是单个CPU,就是第0位设置为1。虽然系统里有多个CPU存在,但是每个CPU不一定可以使用,或者没有初始化,在内核使用cpu_online_map位图来表示那些CPU可以运行内核代码和接受中断处理。随着移动系统的节能需求,需要对CPU进行节能处理,比如有多个CPU运行时可以提高性能,但花费太多电能,导致电池不耐用,需要减少运行的CPU个数,或者只需要一个CPU运行。这样内核又引入了一个cpu_possible_map位图,表示最多可以使用多少个CPU。在本函数里就是依次设置这三个位图的标志,让引导的CPU物理上存在,已经初始化好,最少需要运行的CPU。)*/

【529】page_address_init();【mm/highmem.c  478】

/*初始化高端内存的映射表 (在这里引入了高端内存的概念,那么什么叫做高端内存呢?为什么要使用高端内存呢?其实高端内存是相对于低端内存而存在的,那么先要理解一下低端内存了。在32位的系统里,最多能访问的总内存是4G,其中3G空间给应用程序,而内核只占用1G的空间。因此,内核能映射的内存空间,只有1G大小,但实际上比这个还要小一些,大概是896M,另外128M空间是用来映射高端内存使用的。因此0到896M的内存空间,就叫做低端内存,而高于896M的内存,就叫高端内存了。如果系统是64位系统,当然就没未必要有高端内存存在了,因为64位有足够多的地址空间给内核使用,访问的内存可以达到10G都没有问题。在32位系统里,内核为了访问超过1G的物理内存空间,需要使用高端内存映射表。比如当内核需要读取1G的缓存数据时,就需要分配高端内存来使用,这样才可以管理起来。使用高端内存之后,32位的系统也可以访问达到64G内存。在移动操作系统里,目前还没有这个必要,最多才1G多内存)*/

【530】pr_notice("%s", linux_banner);【include/linux/printk.h  244】

/*输出各种信息(Linux_banner是在kernel/init/version.c中定义的,这个字符串是编译脚本自动生成的)*/

【530】setup_arch(&command_line);【arch/x86/kernel/setup.c  857】

/*很重要的一个函数arch/arm/kernel/setup.c 
(内核架构相关初始化函数,是非常重要的一个初始化步骤。其中包含了处理器相关参数的初始化、内核启动参数(tagged list)的获取和前期处理、内存子系统的早期初始化(bootmem分配器))*/

【532】mm_init_cpumask(&init_mm);【/include/linux/mm_types.h  459】

/*每一个任务都有一个mm_struct结构来管理内存空间,init_mm是内核的mm_struct*/

【533】setup_command_line(command_line);【371】

/*对cmdline进行备份和保存*/

【534】setup_nr_cpu_ids();【kernel/smp.c  538】

/*设置最多有多少个nr_cpu_ids结构*/

【535】setup_per_cpu_areas();【arch/x86/kernel/setup_percpu.c  167】

/*为系统中每个CPU的per_cpu变量申请空间,同时拷贝初始化段里数据(.data.percpu)*/

【536】smp_prepare_boot_cpu();【arch/x86/include/asm/smp.h  102】

/*为SMP系统里引导CPU(boot-cpu)进行准备工作。在ARM系统单核里是空函数*/

【538】build_all_zonelists(NULL, NULL);【mm/page_alloc.c  3865】

/*设置内存管理相关的node(节点,每个CPU一个内存节点)和其中的zone(内存域,包含于节点中,如)数据结构,以完成内存管理子系统的初始化,并设置bootmem分配器*/

【539】page_alloc_init();【mm/page_alloc.c  5567】

/*设置内存页分配通知器*/

【541】pr_notice("Kernel command line: %s\n", boot_command_line);【】见前面

【542】parse_early_param();【445】

/*解析cmdline中的启动参数*/

【543】after_dashes = parse_args("Booting kernel",static_command_line, __start___param,__stop___param - __start___param,-1, -1, &unknown_bootoption);【kernel/params.c  191】

/*这行代码主要对传入内核参数进行解释,如果不能识别的命令就调用最后参数的函数*/

【551】jump_label_init();【include/linux/jump_label.h  146】

【557】setup_log_buf(0);【kernel/printk/printk.c  887】

/*使用bootmeme分配一个记录启动信息的缓冲区*/

【558】pidhash_init();【kernel/pid.c  572】

/*进程ID的HASH表初始化,用bootmem分配并初始化PID散列表,由PID分配器管理空闲和已指派的PID,这样可以提供通PID进行高效访问进程结构的信息。LINUX里共有四种类型的PID,因此就有四种HASH表相对应。*/

【559】vfs_caches_init_early();【fs/dcache.c  3410】

/*前期虚拟文件系统(vfs)的缓存初始化*/

【560】sort_main_extable();【kernel/extable.c   42】

/*对内核异常表(exception table)按照异常向量号大小进行排序,以便加速访问*/

【561】trap_init();【arch/x86/kernel/traps.c  792】

/*对内核陷阱异常进行初始化,在ARM系统里是空函数,没有任何的初始化*/

【562】mm_init();【486】

/*标记哪些内存可以使用,并且告诉系统有多少内存可以使用,当然是除了内核使用的内存以外 
(初始化内核内存分配器,包括六个子函数 
1、page_cgroup_init_flatmem();获取page_cgroup所需内存 
2、mem_init;关闭并释放bootmem分配器,打印内存信息,内核启动时看到Virtual kernel memory layout:的信息就是这个函数的

3、kmem_cache_init();初始化slab分配器 
4、percpu_init_late();PerCPU变量系统后期初始化 
5、pgtable_cache_init();也表缓存初始化,arm中是个空函数 6、vmalloc_init();初始化虚拟内存分配器*/

【569】sched_init();【kernel/sched/core.c  6998】

/*对进程调度器的数据结构进行初始化,创建运行队列,设置当前任务的空线程,当前任务的调度策略为CFS调度器 */

【574】preempt_disable();【】

/*关闭优先级调度。由于每个进程任务都有优先级,目前系统还没有完全初始化,还不能打开优先级调度。*/

【575】if (WARN(!irqs_disabled(),"Interrupts were enabled *very* early, fixing it\n"))  {local_irq_disable();}【】

/*这段代码主要判断是否过早打开中断,如果是这样,就会提示,并把中断关闭*/

【578】idr_init_cache();【lib/idr.c  826】

/*为IDR机制分配缓存,主要是为 structidr_layer结构体分配空间*/

【579】rcu_init();【kernel/rcu/tree.c  3749】

/*初始化直接读拷贝更新的锁机制。 Read-Copy Update (RCU主要提供在读取数据机会比较多,但更新比较的少的场合,这样减少读取数据锁的性能低下的问题。)*/

【580】context_tracking_init();【kernel/context_tracking.c  169】

【581】radix_tree_init();【lib/radix-tree.c  1480】

/*内核radis 树算法初始化*/

【583】early_irq_init();【kernel/irq/irqdesc.c  230】

/*前期外部中断描述符初始化,主要初始化数据结构*/

【584】init_IRQ();【arch/x86/kernel/irqinit.c  84】

/*对应架构特定的中断初始化函数,在ARM中就是machine_desc->init_irq(),就是运行设备描述结构体中的init_irq函数[arch/arm/mach-msm/board-xxx.c]*/

【585】tick_init();【kernel/time/tick-common.c   400】

/*初始化内核时钟系统,tick control,调用clockevents_register_notifier,就是监听时钟变化事件 (这个函数主要作用是初始化时钟事件管理器的回调函数,比如当时钟设备添加时处理。在内核里定义了时钟事件管理器,主要用来管理所有需要周期性地执行任务的设备)*/

【586】rcu_init_nohz();【】

【587】init_timers();【kernel/time/timer.c   1671】

/*初始化引导CPU的时钟相关的数据结构,注册时钟的回调函数,当时钟到达时可以回调时钟处理函数,最后初始化时钟软件中断处理*/

【588】hrtimers_init();【kernel/time/hrtimer.c  1742】

/*初始化高精度的定时器,并设置回调函数。*/

【589】softirq_init();【/kernel/softirq.c  630】

/*初始化软件中断,软件中断与硬件中断区别就是中断发生时,软件中断是使用线程来监视中断信号,而硬件中断是使用CPU硬件来监视中断。*/

【590】timekeeping_init();【kernel/time/timekeeping.c  993】

/*初始化系统时钟计时,并且初始化内核里与时钟计时相关的变量。*/

【591】time_init();【arch/x86/kernel/time.c   94】

/*初始化系统时钟。开启一个硬件定时器,开始产生系统时钟就是system_timer的初始化,arch/arm/mach-msm/board-*.c */

【592】sched_clock_postinit();【kernel/time/sched_clock.c   172】

【593】perf_event_init();【kernel/events/core.c   8208】

/*CPU性能监视机制初始化,此机制包括CPU同一时间执行指令数,cache miss数,分支预测失败次数等性能参数*/

【594】profile_init();【/kernel/profile.c   99】

/*分配内核性能统计保存的内存,以便统计的性能变量可以保存到这里*/

【595】call_function_init();【kernel/smp.c   89】

/*初始化所有CPU的call_single_queue,同时注册CPU热插拔通知函数到CPU通知链中*/

【596】WARN(!irqs_disabled(), "Interrupts were enabled early\n");   early_boot_irqs_disabled = false;   local_irq_enable();【】

/*对应前面的local_irq_disable() (打开本CPU的中断,也即允许本CPU处理中断事件,在这里打开引CPU的中断处理。如果有多核心,别的CPU还没有打开中断处理。)*/

【600】kmem_cache_init_late();【/mm/slub.c   3612】

/*这是内核内存缓存(slab分配器)的后期初始化,当初始化完成之后,就可以使用通用内存缓存了*/

【607】console_init();【drivers/tty/tty_io.c   3510】

/*初始化控制台,从这个函数之后就可以输出内容到控制台了。在这个函数初化之前,都没有办法输出内容,就是输出,也是写到输出缓冲区里,缓存起来,等到这个函数调用之后,就立即输出内容*/

【608】if (panic_later)  panic("Too many boot %s vars at `%s'", panic_later,panic_param);【】

/*判断分析输入的参数是否出错,如果有出错,就启动控制台输出之后,立即打印出错的参数,以便用户立即看到出错的地方。*/

【612】lockdep_info();【kernel/locking/lockdep.c   3997】

/*打印锁的依赖信息,用来调试锁。通过这个函数可以查看目前锁的状态,以便可以发现那些锁产生死锁,那些锁使用有问题。*/

【619】locking_selftest();【lib/locking-selftest.c   1795】

/*测试锁的API是否使用正常,进行自我测试。比如测试自旋锁、读写锁、一般信号量和读写信号量。*/

【621】

#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【】

/*检查initrd的位置是否符合要求,也就是判断传递进来initrd_start对应的物理地址是否正常,如果有误就打印错误信息,并清零initrd_start。*/

【630】page_cgroup_init();【mm/page_cgroup.c   271】

/*初始化容器组的页面内存分配,mem_cgroup是cgroup体系中提供的用于memory隔离的功能,*/

【631】debug_objects_mem_init();【lib/debugobjects.c  1081】

/*这个函数是创建调试对象内存分配初始化,所以紧跟内存缓存初始化后面*/

【632】kmemleak_init();【mm/kmemleak.c   1807】

/*内核内存泄漏检测机制初始化;*/

【633】setup_per_cpu_pageset();【mm/page_alloc.c   4309】

/*创建每个CPU的高速缓存集合数组并初始化,此前只有启动页组。因为每个CPU都不定时需要使用一些页面内存和释放页面内存,为了提高效率,就预先创建一些内存页面作为每个CPU的页面集合。*/

【634】numa_policy_init();【mm/mempolicy.c   2587】

/*初始化NUMA的内存访问策略。所谓NUMA,它是NonUniform Memory AccessAchitecture(非一致性内存访问)的缩写,主要用来提高多个CPU访问内存的速度。因为多个CPU访问同一个节点的内存速度远远比访问多个节点的速度来得快。*/

【635】if (late_time_init) late_time_init();【121】

/*主要运行时钟相关后期的初始化功能。*/

【637】sched_clock_init();【kernel/sched/clock.c   145】

/*对每个CPU进行系统进程调度时钟初始化*/

【638】calibrate_delay();【init/calibrate.c   274】

/*主要计算CPU需要校准的时间,这里说的时间是CPU执行时间。如果是引导CPU,这个函数计算出来的校准时间是不需要使用的,主要使用在非引导CPU上,因为非引导CPU执行的频率不一样,导致时间计算不准确。BogoMIPS值,也是衡量cpu性能的标志*/

【639】pidmap_init();【/kernel/pid.c   586】

/*进程位图初始化,一般情况下使用一页来表示所有进程占用情况。*/

【640】anon_vma_init();【mm/rmap.c   376】

/*初始化反向映射的匿名内存,提供反向查找内存的结构指针位置,快速地回收内存。*/

【641】acpi_early_init();【/drivers/acpi/bus.c   470】

/*这个函数是初始化ACPI电源管理。高级配置及电源接口(Advanced Configuration and Power Interface)ACPI规范介绍ACPI能使软、硬件、操作系统(OS),主机板和外围设备,依照一定的方式管理用电情况,系统硬件产生的Hot-Plug事件,让操作系统从用户的角度上直接支配即插即用设备,不同于以往直接通过基于BIOS 的方式的管理。*/

【642】

#ifdef CONFIG_X86
 if (efi_enabled(EFI_RUNTIME_SERVICES))
  efi_enter_virtual_mode();
#endif【】

/*初始化EFI的接口,并进入虚拟模式。EFI是ExtensibleFirmware Interface的缩写,就是INTEL公司新开发的BIOS接口。*/

【650】thread_info_cache_init();【478】

/*线程信息(thread_info)的缓存初始化。*/

【651】cred_init();【/kernel/cred.c   561】

/*任务信用系统初始化 */

【652】fork_init(totaltam_pages)【kernel/fork.c   652】

/*根据当前物理内存计算出来可以创建进程(线程)的最大数量,并进行进程环境初始化,为task_struct分配空间。*/

【653】proc_caches_init();【kernel/fork.c   1762】

/*进程缓存初始化,为进程初始化创建机制所需的其他数据结构申请空间*/

【654】buffer_init();【fs/buffer.c   3413】

/*初始化文件系统的缓冲区,并计算最大可以使用的文件缓存。*/

【655】key_init();【security/keys/key.c   1123】

/*初始化内核安全键管理列表和结构,内核密钥管理系统*/

【656】security_init();【security/security.c   65】

/*初始化内核安全管理框架,以便提供访问文件/登录等权限。*/

【657】dbg_late_init();【kernel/debug/debug_core.c   839】

/*内核调试系统后期初始化 */

【658】vfs_caches_init(totalram_pages);【/fs/dcache.c   3416】

/*虚拟文件系统进行缓存初始化,提高虚拟文件系统的访问速度*/

【659】signals_init();【kernel/signal.c  3623】

/*初始化信号队列缓存。信号管理系统*/

【661】page_writeback_init();【mm/page-writeback.c   1765】

/*页面写机制初始化 */

【662】proc_root_init();【fs/proc/root.c   165】

/*初始化系统进程文件系统,主要提供内核与用户进行交互的平台,方便用户实时查看进程的信息。*/

【663】cgroup_init();【kernel/cgroup.c   4916】

/*进程控制组正式初始化,主要用来为进程和其子程提供性能控制。比如限定这组进程的CPU使用率为20% */

【664】cpuset_init();【/kernel/cpuset.c   2068】

/*初始化CPUSET,CPUSET主要为控制组提供CPU和内存节点的管理的结构。*/

【665】taskstats_init_early();【kernel/taskstats.c   691】

/*任务状态早期初始化,为结构体获取高速缓存,并初始化互斥机制。任务状态主要向用户提供任务的状态信息。*/

【666】delayacct_init();【kernel/delayacct.c   35】

/*任务延迟机制初始化,初始化每个任务延时计数。当一个任务等CPU运行,或者等IO同步时,都需要计算等待时间。*/

【668】check_bugs();【arch/x86/kernel/cpu/bugs.c   66】

/*检查CPU配置、FPU等是否非法使用不具备的功能,检查CPU BUG,软件规避BUG*/

【670】sfi_init_late();【drivers/sfi/sfi_core.c   500】

/*SFI 初始程序晚期设置函数*/

【677】ftrace_init();【kernel/trace/ftrace.c   4697】

/*功能跟踪调试机制初始化,初始化内核跟踪模块,ftrace的作用是帮助开发人员了解Linux 内核的运行时行为,以便进行故障调试或性能分析 function trace.*/

【680】rest_init();【393】

/*剩余的初始化,至此,内核已经开始工作了*/

Linux内核启动分析的更多相关文章

  1. Linux内核启动分析过程-《Linux内核分析》week3作业

    环境搭建 环境的搭建参考课件,主要就是编译内核源码和生成镜像 start_kernel 从start_kernel开始,才真正进入了Linux内核的启动过程.我们可以把start_kernel看做平时 ...

  2. linux内核启动分析(2)

    -----以下内容为从网络上整理所得------ 主要介绍kernel_init线程(函数),这个线程在rest_init函数中被创建,kernel_init函数将完成设备驱动程序的初始化,并调用in ...

  3. Linux内核启动分析笔记

    一.驱动加载 1.驱动加载调用关系 start_kernel //init/main.c rest_init //最后执行它 kernel_init //使用kernel_thread创建一个进程执行 ...

  4. linux内核启动分析(3)

    主要分析do_basic_setup函数里面的do_initcalls()函数,这个函数用来调用所有编译内核的驱动模块中的初始化函数. static void __init do_initcalls( ...

  5. 通过从代码层面分析Linux内核启动来探知操作系统的启动过程

    通过从代码层面分析Linux内核启动来探知操作系统的启动过程 前言说明 本篇为网易云课堂Linux内核分析课程的第三周作业,我将围绕Linux 3.18的内核中的start_kernel到init进程 ...

  6. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  7. Linux内核及分析 第三周 Linux内核的启动过程

    实验过程: 打开shell终端,执行以下命令: cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage-initrd rootf ...

  8. Linux内核启动流程分析(一)【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-3380535.html 很久以前分析的,一直在电脑的一个角落,今天发现贴出来和大家分享下.由于是word直接 ...

  9. 【内核】linux内核启动流程详细分析

    Linux内核启动流程 arch/arm/kernel/head-armv.S 该文件是内核最先执行的一个文件,包括内核入口ENTRY(stext)到start_kernel间的初始化代码, 主要作用 ...

随机推荐

  1. 第一个shell编程,输出hello world!

    在计算机科学中,Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器).它类似于DOS下的command和后来的cmd.exe.它接收用户命令,然后调用相应的应用程序.--- ...

  2. 在VMware安装Centos再安装Oracle数据库(个人学习使用)

    打开VMware 选择稍后安装 自定义安装 小生安装的是64位的Centos 给虚拟机设置名称和安装位置 设置虚拟机打处理器并分配内存(oracle12G我建议内存为2G以上) 网络类型选择仅主机模式 ...

  3. Java简介(2)-基本概念

    1.抽象类:规定一个或多个抽象方法的类别本身必须定义为abstract,抽象类只是用来派生子类,而不能用它来创建对象 2.final类:又称“最终类”,它只能用来创建对象,而不能被继承,与抽象类刚好相 ...

  4. 转型函数 Boolean()

    布尔值有2种可能的值true和false;但 ECMAScript中所有类型的值都有与这两个 Boolean 值 等价的值.要将一个值转换为其对应的 Boolean 值,可以调用转型函数 Boolea ...

  5. sql server2008附加数据库5120错误

    解决方法: 附加数据库时,显示错误,错误信息为 一种解决方法为,设置mdf文件所在文件夹的权限(有些资料说只设置mdf文件的权限就好,但我试了不管用),在文件夹上右击——属性——安全,如图所示: 选择 ...

  6. 死亡的协议--- Pieter Hintjens (ZeroMQ作者)

    过去几年中用zeromq写过几个系统系统.对ZeroMQ强大和灵活印象非常深刻.在阅读zeromq guide文档时候.发现作者整理各种通信模式非常经典和实用,可以作为分布式通信的教科书来看.第一次见 ...

  7. C# ORM—Entity Framework 之Code first(代码优先)(二)

    一.Entity Framework Code first(代码优先)使用过程 1.1Entity Framework 代码优先简介 不得不提Entity Framework Code First这个 ...

  8. Web Service相关工具的配置

    近期在学习Web Service Testing,使用到了soapUI这个工具,但是在学习之前,需要搭建Web Service环境,其中有关数据库的连接问题花费了我好多时间,主要还是自己对于很多配置不 ...

  9. Web日志分析

    http://www.rising.com.cn/newsletter/news/2013-03-20/13380.html https://www.trustwave.com/Resources/S ...

  10. ClipDrawable 资源

    ClipDrawable 代表从其他位图上截取的一个“图片片段”. 示例: main.xml <?xml version="1.0" encoding="utf-8 ...