Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja

 转自:http://blog.chinaunix.net/uid-25909619-id-4938396.html

    在基本分析完内核启动流程的之后,还有一个比较重要的初始化函数没有分析,那就是do_basic_setup。在内核init线程中调用了do_basic_setup,这个函数也做了很多内核和驱动的初始化工作,详解如下:

  1. /*
  2.  * 好了, 设备现在已经初始化完成。 但是还没有一个设备被初始化过,
  3.  * 但是 CPU 的子系统已经启动并运行,
  4.  * 且内存和处理器管理系统已经在工作了。
  5.  *
  6.  * 现在我们终于可以开始做一些实际的工作了..
  7.  */
  8. static void __init do_basic_setup(void)
  9. {
  10.     cpuset_init_smp();

    点击(此处)折叠或打开

    1. 针对SMP系统,初始化内核control group的cpuset子系统。如果非SMP,此函数为空。
    2. cpuset是在用户空间中操作cgroup文件系统来执行进程与cpu和进程与内存结点之间的绑定。
    3. 本函数将cpus_allowed和mems_allwed更新为在线的cpu和在线的内存结点,并为内存热插拨注册了钩子函数,最后创建一个单线程工作队列cpuset。
  11.     usermodehelper_init();

    点击(此处)折叠或打开

    1. 创建一个单线程工作队列khelper。运行的系统中只有一个,主要作用是指定用户空间的程序路径和环境变量, 最终运行指定的user space的程序,属于关键线程,不能关闭。
  12.     init_tmpfs();

    点击(此处)折叠或打开

    1. 初始化内核tmpfs文件系统
  13.     driver_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的各子系统,可见的现象是在/sys中出现的目录和文件
  14.     init_irq_proc();

    点击(此处)折叠或打开

    1. 在proc文件系统中创建irq目录,并在其中初始化系统中所有中断对应的目录。
  15.     do_ctors();

    点击(此处)折叠或打开

    1. 调用链接到内核中的所有构造函数,也就是链接进.ctors段中的所有函数。
    2. 在Linux-2.6.31开始内核启动增加了对构造函数的支持。
    3. git提交:

      点击(此处)折叠或打开

      1. commit b99b87f70c7785ab1e253c6220f4b0b57ce3a7f7
      2. Author: Peter Oberparleiter<oberpar@linux.vnet.ibm.com>
      3. Date: Wed Jun 17 16:28:03 2009 -0700
      4. kernel: constructor support

       内核:构造函数支持

      1. Call constructors (gcc-generated initcall-like functions) during kernel
      2. start and module load. Constructors are e.g. used for gcov data
      3. initialization.
      4. 在内核启动和模块挂载时,调用构造函数(gcc生成的类初始化函数)。构造函数就是
      5. 比如用于初始化gcov数据的函数
      6. Disable constructor support for usermode Linux to prevent conflicts with
      7. host glibc.
      8. 对于Linux的用户模式禁用构造函数支持,以避免和glibc冲突。
      9. Signed-off-by: Peter Oberparleiter<oberpar@linux.vnet.ibm.com>
      10. Acked-by: Rusty Russell<rusty@rustcorp.com.au>
      11. Acked-by: WANG Cong<xiyou.wangcong@gmail.com>
      12. Cc: Sam Ravnborg<sam@ravnborg.org>
      13. Cc: Jeff Dike<jdike@addtoit.com>
      14. Cc: Andi Kleen<andi@firstfloor.org>
      15. Cc: Huang Ying<ying.huang@intel.com>
      16. Cc: Li Wei<w.li@sun.com>
      17. Cc: Michael Ellerman<michaele@au1.ibm.com>
      18. Cc: Ingo Molnar<mingo@elte.hu>
      19. Cc: Heiko Carstens<heicars2@linux.vnet.ibm.com>
      20. Cc: Martin Schwidefsky<mschwid2@linux.vnet.ibm.com>
      21. Cc: Al Viro<viro@zeniv.linux.org.uk>
      22. Signed-off-by: Andrew Morton<akpm@linux-foundation.org>
      23. Signed-off-by: Linus Torvalds<torvalds@linux-foundation.org>

      $ git tag --contains b99b87f7

      v2.6.31

      v2.6.31-rc1

      v2.6.31-rc2

      v2.6.31-rc3

      v2.6.31-rc4

      v2.6.31-rc5

      v2.6.31-rc6

      v2.6.31-rc7

      v2.6.31-rc8

      v2.6.31-rc9

      v2.6.32

      v2.6.32-rc1

      v2.6.32-rc2

      v2.6.32-rc3

      v2.6.32-rc4

      v2.6.32-rc5

      v2.6.32-rc6

      v2.6.32-rc7

      v2.6.32-rc8

  16.     do_initcalls();

    点击(此处)折叠或打开

    1. 调用所有编译内核的驱动模块中的初始化函数。
    2. 这里就是驱动程序员需要关心的步骤,其中按照各个内核模块初始化函数所自定义的启动级别(1~7),按顺序调用器初始化函数。
    3. 对于同一级别的初始化函数,安装编译是链接的顺序调用,也就是和内核Makefile的编写有关。

      在编写内核模块的时候需要知道这方面的知识,比如你编写的模块使用的是I2C的API,那你的模块的初始化函数的级别必须低于I2C子系统初始化函数的级别(也就是级别数(1~7)要大于I2C子系统)。如果编写的模块必须和依赖的模块在同一级,那就必须注意内核Makefile的修改了。

      这方面的知识会在有空的时候总结下,网上也有相关的文章。

     

  17. }

上面的函数调用了driver_init函数,作用是驱动模型子系统的初始化,对于内核驱动工程师来说比较重要,详解如下:

drivers/base/init.c:

  1. /**
  2.  * driver_init - 初始化驱动模型.
  3.  *
  4.  * 调用驱动模型初始化函数来初始化它们的子系统。
  5.  * 由早期的init/main.c中调用。
  6.  */
  7. void __init driver_init(void)
  8. {
  9.     /* 它们为核心部件 */
  10.     devtmpfs_init();

    点击(此处)折叠或打开

    1. 初始化devtmpfs文件系统,驱动核心设备将在这个文件系统中添加它们的设备节点。
    2. 这个文件系统可以由内核在挂载根文件系统之后自动挂载到/dev下,也可以在文件系统的启动脚本中手动挂载。
  11.     devices_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的部分子系统和kobject:
    2. devices
    3. dev
    4. dev/block
    5. dev/char
  12.     buses_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的bus子系统
  13.     classes_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的class子系统
  14.     firmware_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的firmware子系统
  15.     hypervisor_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的hypervisor子系统
  16.     /* 这些也是核心部件, 但是必须
  17.      * 在以上核心中的核心部件之后调用。
  18.      */
  19.     platform_bus_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的bus/platform子系统
  20.     system_bus_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的devices/system子系统
  21.     cpu_dev_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的devices/system/cpu子系统
  22.     memory_dev_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的devices/system/memory子系统
    2. 虽然从代码上看这样,但是我在实际的系统中并没有找到/sys/devices/system/memory这个目录
  23. }
时间: 2024-11-18 06:05:15

Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】的相关文章

Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】

原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja  转自:http://blog.chinaunix.net/uid-25909619-id-4938390.html   在构架相关的汇编代码运行完之后,程序跳入了构架无关的内核C语言代码:init/main.c中的start_kernel函数,在这个函数中Linux内核开始真正进入初始化阶段,      下面我就顺这代码逐个函数的解释,但是这

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja  转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html     前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并

Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja  转自:http://blog.chinaunix.net/uid-25909619-id-4938393.html 在分析start_kernel函数的时候,其中有构架相关的初始化函数setup_arch. 此函数根据构架而异,对于ARM构架的详细分析如下: void __init setup_arch(char **cmdli

Linux内核源码分析--内核启动之(1)zImage自解压过程(Linux-3.0 ARMv7) 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-4938388.html   研究内核源码和内核运行原理的时候,很总要的一点是要了解内核的初始情况,也就是要了解内核启动过程.我在研究内核的内存管理的时候,想知道内核启动后的页表的放置,页表的初始化等信息,这促使我这次仔细地研究内核的启动代码.       CPU在bootloader的帮助下将内核载入到了内存中,并开始执行.当然,bootloader必须为zImage做好必要的准备:  1. CPU 寄存

Linux内核源码分析--内核启动之(2)Image内核启动(汇编部分)(Linux-3.0 ARMv7) 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-4938389.html  在完成了zImage自解压之后,就跳转到了解压后的内核(也就是vmlinux的bin版本Image),具体的入口可以在arch/arm/kernel/vmlinux.lds.S(最终的链接脚本是通过这个文件产生的)中获得:   ...... SECTIONS { #ifdef CONFIG_XIP_KERNEL . = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_

kernel 3.10内核源码分析--TLB相关--TLB概念、flush、TLB lazy模式 【转】

  转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&id=4808877&uid=14528823   一.概念及基本原理 TLB即Translation Lookaside Buffer,是MMU中的一种硬件cache,用于缓存页表,即缓存线性地址(虚拟地址)到物理地址的映射关系. 如果没有TLB,那么正常的内存数据访问前需要先通过线性地址查进程页表将其转换为物理地址,页表实际也是放在物理内存中的,页表分级存放,一次地址转换需

《深入理解Spark:核心思想与源码分析》——3.8节TaskScheduler的启动

3.8 TaskScheduler的启动3.6节介绍了任务调度器TaskScheduler的创建,要想TaskScheduler发挥作用,必须要启动它,代码如下.taskScheduler.start()TaskScheduler在启动的时候,实际调用了backend的start方法. override def start() { backend.start() } 以LocalBackend为例,启动LocalBackend时向actorSystem注册了LocalActor,见代码清单3-3

《深入理解Spark:核心思想与源码分析》——3.7节创建和启动DAGScheduler

3.7 创建和启动DAGSchedulerDAGScheduler主要用于在任务正式交给TaskSchedulerImpl提交之前做一些准备工作,包括:创建Job,将DAG中的RDD划分到不同的Stage,提交Stage,等等.创建DAG-Scheduler的代码如下. @volatile private[spark] var dagScheduler: DAGScheduler = _ dagScheduler = new DAGScheduler(this) DAGScheduler的数据结

《深入理解Spark:核心思想与源码分析》——3.10节创建和启动ExecutorAllocationManager

3.10 创建和启动ExecutorAllocationManager ExecutorAllocationManager用于对已分配的Executor进行管理,创建和启动Executor-AllocationManager的代码如下. private[spark] val executorAllocationManager: Option[ExecutorAllocationManager] = if (conf.getBoolean("spark.dynamicAllocation.enab