linux 内核 之 start_kernel()

来源:互联网 发布:java三大设计模式 编辑:程序博客网 时间:2024/05/22 01:31
//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();}

原创粉丝点击